package com.xhsj.user.hr.process.hrLeaveProcess.service;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.xhsj.user.hr.process.dto.hrLeaveProcess.*;
import com.xhsj.user.hr.process.dto.processDefinition.HandleAuditDto;
import com.xhsj.user.hr.process.hrBecomeRegular.service.TbHrApprovalBecomeRegularApplyService;
import com.xhsj.user.hr.process.hrEntryProcess.mapper.TbHrApprovalEntryApplyMapper;
import com.xhsj.user.hr.process.hrLeaveProcess.entity.TbHrApprovalLeaveApply;
import com.xhsj.user.hr.process.hrLeaveProcess.entity.TbHrApprovalLeaveHistoryTime;
import com.xhsj.user.hr.process.hrLeaveProcess.entity.TbHrApprovalLeaveTime;
import com.xhsj.user.hr.process.hrLeaveProcess.mapper.TbHrApprovalLeaveApplyMapper;
import com.xhsj.user.hr.process.hrLeaveProcess.mapper.TbHrApprovalLeaveHistoryTimeMapper;
import com.xhsj.user.hr.process.hrLeaveProcess.mapper.TbHrApprovalLeaveTimeMapper;
import com.xhsj.user.hr.process.hrLeaveProcess.query.*;
import com.xhsj.user.hr.base.BaseService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xhsj.user.hr.process.hrLeaveProcess.vo.FindToDoListVo;
import com.xhsj.user.hr.process.hrLeaveProcess.vo.LeaveUsableLengthVo;
import com.xhsj.user.hr.process.overtime.mapper.TbHrOvertimeApplyMapper;
import com.xhsj.user.hr.process.processDefinition.entity.TbGlobalApprovalHiTask;
import com.xhsj.user.hr.process.processDefinition.entity.TbGlobalApprovalTask;
import com.xhsj.user.hr.process.processDefinition.mapper.TbGlobalApprovalHiTaskMapper;
import com.xhsj.user.hr.process.processDefinition.mapper.TbGlobalApprovalTaskMapper;
import com.xhsj.user.hr.process.processDefinition.mapper.TbGlobalWorkFlowNodeMapper;
import com.xhsj.user.hr.process.processDefinition.query.ProcessNodeQuery;
import com.xhsj.user.hr.process.processDefinition.service.TbGlobalApprovalHiTaskService;
import com.xhsj.user.hr.process.processDefinition.service.TbGlobalApprovalTaskService;
import com.xhsj.user.hr.process.processDefinition.service.TbGlobalWorkFlowNodeService;
import com.xhsj.user.hr.process.query.ApprovalQuery;
import com.xhsj.user.hr.system.entity.*;
import com.xhsj.user.hr.system.mapper.*;
import com.xhsj.user.hr.system.service.TbHrUserSocialSecurityService;
import com.xhsj.user.hr.system.vo.LeaveTimeVo;
import com.xhsj.user.lsm.mapper.TbBadgesUseApplyMapper;
import com.xhsj.user.properties.RoleKeyNameProperites;
import com.xhsj.user.security.entity.LoginUser;
import com.xhsj.user.hr.system.service.TbHrLeaveSettingService;
import com.xhsj.user.utils.*;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import java.io.Serializable;
import java.util.concurrent.*;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import lombok.extern.slf4j.Slf4j;



/**
 * <p>
 * 流程-hr请假申请表 服务实现类
 * </p>
 *
 * @author liuqinghua
 * @since Sep 1, 2020 10:07:11 AM
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
//@CacheConfig(cacheNames = "TbHrApprovalLeaveApply")
public class TbHrApprovalLeaveApplyService extends BaseService<TbHrApprovalLeaveApplyMapper, TbHrApprovalLeaveApply> {
    @Autowired
    private TbHrApprovalLeaveApplyMapper dao;

    @Autowired
    private TbHrApprovalLeaveTimeService tbHrApprovalLeaveTimeService;

    @Autowired
    private TbHrApprovalLeaveTimeMapper tbHrApprovalLeaveTimeMapper;

    @Autowired
    private TbHrApprovalLeaveHistoryTimeMapper tbHrApprovalLeaveHistoryTimeMapper;

    @Autowired
    private TbGlobalApprovalTaskService tbGlobalApprovalTaskService;

    @Autowired
    private TbGlobalApprovalTaskMapper tbGlobalApprovalTaskMapper;

    @Autowired
    private TbGlobalWorkFlowNodeMapper tbGlobalWorkFlowNodeMapper;

    @Autowired
    private TbGlobalWorkFlowNodeService tbGlobalWorkFlowNodeService;

    @Autowired
    private TbGlobalRoleMapper tbGlobalRoleMapper;

    @Autowired
    private TbGlobalApprovalHiTaskService tbGlobalApprovalHiTaskService;

    @Autowired
    private TbHrApprovalBecomeRegularApplyService tbHrApprovalBecomeRegularApplyService;

    @Autowired
    private TbHrOvertimeApplyMapper tbHrOvertimeApplyMapper;

    @Autowired
    private TbHrLeaveUsableLengthMapper tbHrLeaveUsableLengthMapper;
    @Autowired
    private TbHrLeaveSettingService tbHrLeaveSettingService;

    @Autowired
    private TbBadgesUseApplyMapper tbBadgesUseApplyMapper;

    @Autowired
    private TbHrUserSocialSecurityService tbHrUserSocialSecurityService;

    // 流程节点
    @Autowired
    private TbGlobalWorkFlowNodeMapper processNodeMapper;

    @Autowired
    private RoleKeyNameProperites roleKeyNameProperites;

    @Autowired
    private TbGlobalUserMapper userMapper;

    @Autowired
    private TbGlobalApprovalHiTaskMapper tbGlobalApprovalHiTaskMapper;

    @Autowired
    private TbHrApprovalEntryApplyMapper tbHrApprovalEntryApplyMapper;

    @Autowired
    private TbHrLeaveUseNumMapper tbHrLeaveUseNumMapper;

    @Autowired
    private TbHrLeaveHiUseNumMapper tbHrLeaveHiUseNumMapper;

    @Autowired
    private TbHrUserSocialSecurityMapper tbHrUserSocialSecurityMapper;
    /**
     * 保存
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    @Override
    //@CacheEvict(cacheNames="TbHrApprovalLeaveApply", allEntries=true)
    public boolean save(TbHrApprovalLeaveApply entity) {
        return super.save(entity);
    }

    /**
     * 通过id获取数据
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    @Override
    //@Cacheable(key = "#id",sync = true)
    public TbHrApprovalLeaveApply getById(Serializable id) {
        return super.getById(id);
    }

    /**
     * 通过id删除数据
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    @Override
    //@CacheEvict(cacheNames="TbHrApprovalLeaveApply", allEntries=true)
    public boolean removeById(Serializable id) {
        return super.removeById(id);
    }

    /**
     * 批量删除数据
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    //@CacheEvict(cacheNames="SysDict", allEntries=true)
    @Override
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        return super.removeByIds(idList);
    }

    /**
     * 分页查询数据
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    //@Cacheable(key = "#data",sync = true)
    public IPage<TbHrApprovalLeaveApply> selectPage(Map<String, Object> data) {
        int currentPage = 1;
        if (!Objects.isNull(data.get("page"))) {
            currentPage = (Integer) data.get("page");
        }
        int pageSize = 20;
        if (!Objects.isNull(data.get("size"))) {
            pageSize = (Integer) data.get("size");
        }

        TbHrApprovalLeaveApply entity = JSON.parseObject(JSON.toJSONString(data), TbHrApprovalLeaveApply.class);
        Page<TbHrApprovalLeaveApply> page = new Page(currentPage, pageSize);
        QueryWrapper<TbHrApprovalLeaveApply> wrapper = new QueryWrapper(entity);
        return super.selectPage(page, wrapper);
    }

    /**
     * 查询所有数据
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    @Override
    //@Cacheable(value = "TbHrApprovalLeaveApply",sync = true)
    public List<TbHrApprovalLeaveApply> selectAll() {
        return super.selectAll();
    }


    /**
     * 请假流程启动
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    public ApprovalQuery startLeaveApply(HrLeaveApplyStartDto data) throws Exception {

        // 保存流程-hr请假申请表
        TbHrApprovalLeaveApply apply = data.getApply();
        if (!super.save(apply)) {
            throw new Exception("保存流程-hr请假申请表异常");
        }

        // 拆分数据
        List<TbHrApprovalLeaveTime> tbHrApprovalLeaveTimes = splitDate(data.getTimeList(), apply);
        data.setTimeList(tbHrApprovalLeaveTimes);

        this.saveTbHrApprovalLeaveTime(tbHrApprovalLeaveTimes, apply);

        if (data.getApply().getVacationId() == 3) { // 年假
            TbHrUserSocialSecurity userSocialSecurity = tbHrUserSocialSecurityService.getUserSocialSecurity(UserUtils.getLoginAppUser().getUserId(),apply.getId());
            if (userSocialSecurity == null) {
                TbHrUserSocialSecurity socialSecurity = data.getSocialSecurity();
                if (socialSecurity == null) {
                    throw new Exception("请上传社保凭证pdf文档");
                }
                // 社保凭证为空的话  直接让行政助理审核
                TbHrUserSocialSecurity tbHrUserSocialSecurity = new TbHrUserSocialSecurity();
                BeanUtils.copyProperties(data.getSocialSecurity(),tbHrUserSocialSecurity);
                tbHrUserSocialSecurity.setUserId(UserUtils.getLoginAppUser().getUserId());
                tbHrUserSocialSecurityService.save(tbHrUserSocialSecurity);

                return handleSocialSecurity(apply);
            } else {
                // 检验年假时间
                TbHrLeaveUseNum tbHrLeaveUseNum = checkTiem(tbHrApprovalLeaveTimes, userSocialSecurity);
                tbHrLeaveUseNum.setPreUseNum(tbHrLeaveUseNum.getPreUseNum() > 0 ? tbHrLeaveUseNum.getPreUseNum() : 0);
                tbHrLeaveUseNum.setUseNum(tbHrLeaveUseNum.getUseNum()>0?tbHrLeaveUseNum.getUseNum():0);
                if(tbHrLeaveUseNum.getId() != null){
                    int i = tbHrLeaveUseNumMapper.updateById(tbHrLeaveUseNum);
                    if(i != 1){
                        throw new Exception("修改年假已休表异常");
                    }
                }else{
                    // 修改今年年假已用时长和去年年假已用时长根据id
                    tbHrLeaveUseNum.setSocialSecurityId(userSocialSecurity.getId());
                    if( tbHrLeaveUseNumMapper.insert(tbHrLeaveUseNum) != 1){
                        throw new Exception("修改年假已休表异常");
                    }
                }

            }
        }

        //  执行开始请假流程启动
        return startLeaveApplyRun(apply);
    }

    // 校验时间
    public TbHrLeaveUseNum checkTiem( List<TbHrApprovalLeaveTime> tbHrApprovalLeaveTimes,
                                      TbHrUserSocialSecurity userSocialSecurity) throws Exception {
        int year = LocalDate.now().getYear();
        // 获取去年的请假时间和去年已休时间
        QueryWrapper<TbHrLeaveUseNum> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("social_security_id",userSocialSecurity.getId());
        queryWrapper.eq("year",year);
        TbHrLeaveUseNum tbHrLeaveUseNum = tbHrLeaveUseNumMapper.selectOne(queryWrapper);
        if(tbHrLeaveUseNum == null)
            tbHrLeaveUseNum = new TbHrLeaveUseNum();
        // 今年已休时间
        userSocialSecurity.setUseNum(tbHrLeaveUseNum.getUseNum());
        // 去年的年假时长
        int preTotalNum = tbHrLeaveUseNum.getPreTotalNum();
        // 去年已休时间
        int preUseNum = tbHrLeaveUseNum.getPreUseNum();
        // 去年结余
        int preNum =preTotalNum-preUseNum;

        if (preNum<0) {
            BigDecimal bigDecimal = new BigDecimal(preUseNum);
            BigDecimal bigDecimal1 = new BigDecimal(preNum);
            BigDecimal abs = bigDecimal1.abs();
            BigDecimal subtract = bigDecimal.subtract(abs);
            preUseNum = subtract.intValue();
        }
        preNum =preNum<0?0:preNum;
        // 获取年假过期时间
        QueryWrapper<TbHrLeaveSetting> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("del_flag",0);
        List<TbHrLeaveSetting> list = tbHrLeaveSettingService.list(queryWrapper1);
        if(list == null){
            throw new Exception("年假过期时间限制不能为空");
        }
        TbHrLeaveSetting tbHrLeaveSetting = list.get(0);
        String annualLeaveExpireDate = tbHrLeaveSetting.getAnnualLeaveExpireDate();
        // 时间限制
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String limitTime = year+"-"+annualLeaveExpireDate;
        LocalDate limitDateEnd = LocalDate.parse(limitTime, fmt);
        LocalDate limitDateStart = LocalDate.parse(year+"-"+"01-01", fmt);
        // 此操请假总时长
        int sum = tbHrApprovalLeaveTimes.stream().mapToInt(item -> item.getDays().intValue()).sum();

        // 今年年假时间
        int available = userSocialSecurity.getTotalNumber();
        // 今年已休时间
        int useNumber = userSocialSecurity.getUseNumber();
        // 今年结余
        int num =available-useNumber;

        // 获取请假单里含有去年的数据
        List<TbHrApprovalLeaveTime> collect = tbHrApprovalLeaveTimes.stream().filter(it ->
                (year-1) == LocalDateTime.ofInstant(it.getStartDate().toInstant(), ZoneId.systemDefault()).getYear()).
                collect(Collectors.toList());
        int preSum = collect.stream().mapToInt(item -> item.getDays().intValue()).sum();

        // 限制时间外数据
        List<TbHrApprovalLeaveTime> collect1 = tbHrApprovalLeaveTimes.stream().filter(it ->
                limitDateEnd.isBefore(LocalDateTime.ofInstant(it.getStartDate().toInstant(), ZoneId.systemDefault()).toLocalDate())).
                collect(Collectors.toList());
        int preSum1 = collect1.stream().mapToInt(item -> item.getDays().intValue()).sum();

        // 限制时间内数据 今年
        List<TbHrApprovalLeaveTime> collect2 = tbHrApprovalLeaveTimes.stream().filter(it ->
                limitDateStart.isBefore(LocalDateTime.ofInstant(it.getStartDate().toInstant(), ZoneId.systemDefault()).toLocalDate()) &&limitDateEnd.isAfter(LocalDateTime.ofInstant(it.getStartDate().toInstant(), ZoneId.systemDefault()).toLocalDate())).
                collect(Collectors.toList());
//        int preSum2 = collect2.stream().mapToInt(item -> item.getDays().intValue()).sum();

        TbHrLeaveHiUseNum tbHrLeaveHiUseNum= new TbHrLeaveHiUseNum();

        tbHrLeaveHiUseNum.setDataId(tbHrApprovalLeaveTimes.get(0).getDataId());

        // 先判断去年和限制外
        if(collect1.size()>0){
            if (available <preSum1 + useNumber) {
                throw new Exception("可用年假时长不够,当前年剩余年假"+(available-useNumber)+"小时");
            }
        }

        if(collect.size()>0){
            if (preTotalNum <preSum + preUseNum) {
                throw new Exception("你有补去年假但去年年假时长不够,去年剩余年假" + (preTotalNum - preUseNum) + "小时");
            }
        }

        // 只有限制时间外得数据 值判断今年结余
        if(collect1.size()>0 &&collect2.size()==0 && collect.size() == 0){
            if (available <sum + useNumber) {
                throw new Exception("可用年假时长不够,当前剩余年假"+(available-useNumber)+"小时");
            }
            tbHrLeaveUseNum.setUseNum(sum + useNumber);
            tbHrLeaveHiUseNum.setUseNum(sum);
        }else if(collect1.size()==0 &&collect2.size()==0 && collect.size()> 0){  // 只有去年得数据
            if (preTotalNum < sum + preUseNum) {
                throw new Exception("你有补去年假但去年年假时长不够,去年剩余年假" + (preTotalNum - preUseNum) + "小时");
            }
            tbHrLeaveUseNum.setPreUseNum(sum + preUseNum);
            tbHrLeaveHiUseNum.setPreUseNum(sum);
        }else {
            if (preTotalNum+available < sum+useNumber+preUseNum) {
                throw new Exception("可用年假时长不够,当前剩余年假"+((available-useNumber)+(preTotalNum-preUseNum))+"小时");
            }
            if(collect1.size()>0){
                tbHrLeaveUseNum.setUseNum(preSum1+useNumber);
                sum = sum-preSum1;
                tbHrLeaveHiUseNum.setUseNum(preSum1);

            }
            // 去年结余大于休假时间
            if (preNum>sum) {
                tbHrLeaveUseNum.setPreUseNum(preUseNum+sum);
                tbHrLeaveHiUseNum.setPreUseNum(sum);
            }else {
                tbHrLeaveUseNum.setPreUseNum(preTotalNum);
                tbHrLeaveUseNum.setUseNum(tbHrLeaveUseNum.getUseNum()+(sum-preNum));
                tbHrLeaveHiUseNum.setUseNum(sum-preNum+preSum1);
                tbHrLeaveHiUseNum.setPreUseNum(preNum);

            }
        }
        tbHrLeaveHiUseNumMapper.insert(tbHrLeaveHiUseNum);
        tbHrLeaveUseNum.setYear(year);
        return  tbHrLeaveUseNum;
    }


    public TbHrLeaveUseNum upDateTime( List<TbHrApprovalLeaveTime> tbHrApprovalLeaveTimes,
                                      TbHrUserSocialSecurity userSocialSecurity) throws Exception {
        int year = LocalDate.now().getYear();
        // 获取去年的请假时间和去年已休时间
        QueryWrapper<TbHrLeaveUseNum> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("social_security_id",userSocialSecurity.getId());
        queryWrapper.eq("year",year);
        TbHrLeaveUseNum tbHrLeaveUseNum = tbHrLeaveUseNumMapper.selectOne(queryWrapper);
//        tbHrLeaveUseNum.setHiUseNum(tbHrLeaveUseNum.getUseNum());
//        tbHrLeaveUseNum.setHiPreUseNum(tbHrLeaveUseNum.getPreUseNum());
        if(tbHrLeaveUseNum == null)
            tbHrLeaveUseNum = new TbHrLeaveUseNum();
        // 今年已休时间
        userSocialSecurity.setUseNum(tbHrLeaveUseNum.getUseNum());
        // 去年的年假时长
        int preTotalNum = tbHrLeaveUseNum.getPreTotalNum();
        // 去年已休时间
        int preUseNum = tbHrLeaveUseNum.getPreUseNum();
        // 去年结余
        int preNum =preTotalNum-preUseNum;

        if (preNum<0) {
            BigDecimal bigDecimal = new BigDecimal(preUseNum);
            BigDecimal bigDecimal1 = new BigDecimal(preNum);
            BigDecimal abs = bigDecimal1.abs();
            BigDecimal subtract = bigDecimal.subtract(abs);
            preUseNum = subtract.intValue();
        }
        preNum =preNum<0?0:preNum;
        // 获取年假过期时间
        QueryWrapper<TbHrLeaveSetting> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("del_flag",0);
        List<TbHrLeaveSetting> list = tbHrLeaveSettingService.list(queryWrapper1);
        if(list == null){
            throw new Exception("年假过期时间限制不能为空");
        }
        TbHrLeaveSetting tbHrLeaveSetting = list.get(0);
        String annualLeaveExpireDate = tbHrLeaveSetting.getAnnualLeaveExpireDate();
        // 时间限制
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String limitTime = year+"-"+annualLeaveExpireDate;
        LocalDate limitDateEnd = LocalDate.parse(limitTime, fmt);
        LocalDate limitDateStart = LocalDate.parse(year+"-"+"01-01", fmt);
        // 此操请假总时长
        int sum = tbHrApprovalLeaveTimes.stream().mapToInt(item -> item.getDays().intValue()).sum();

        // 今年年假时间
        int available = userSocialSecurity.getTotalNumber();
        // 今年已休时间
        int useNumber = userSocialSecurity.getUseNumber();
        // 今年结余
        int num =available-useNumber;

        // 获取请假单里含有去年的数据
        List<TbHrApprovalLeaveTime> collect = tbHrApprovalLeaveTimes.stream().filter(it ->
                (year-1) == LocalDateTime.ofInstant(it.getStartDate().toInstant(), ZoneId.systemDefault()).getYear()).
                collect(Collectors.toList());
        int preSum = collect.stream().mapToInt(item -> item.getDays().intValue()).sum();

        // 限制时间外数据
        List<TbHrApprovalLeaveTime> collect1 = tbHrApprovalLeaveTimes.stream().filter(it ->
                limitDateEnd.isBefore(LocalDateTime.ofInstant(it.getStartDate().toInstant(), ZoneId.systemDefault()).toLocalDate())).
                collect(Collectors.toList());
        int preSum1 = collect1.stream().mapToInt(item -> item.getDays().intValue()).sum();

        // 限制时间内数据 今年
        List<TbHrApprovalLeaveTime> collect2 = tbHrApprovalLeaveTimes.stream().filter(it ->
                limitDateStart.isBefore(LocalDateTime.ofInstant(it.getStartDate().toInstant(), ZoneId.systemDefault()).toLocalDate()) &&limitDateEnd.isAfter(LocalDateTime.ofInstant(it.getStartDate().toInstant(), ZoneId.systemDefault()).toLocalDate())).
                collect(Collectors.toList());
        int preSum2 = collect2.stream().mapToInt(item -> item.getDays().intValue()).sum();

        TbHrLeaveHiUseNum tbHrLeaveHiUseNum= new TbHrLeaveHiUseNum();

        tbHrLeaveHiUseNum.setDataId(tbHrApprovalLeaveTimes.get(0).getDataId());

//        // 先判断去年和限制外
//        if(collect1.size()>0){
//            if (available <preSum1 + useNumber) {
//                throw new Exception("可用年假时长不够,当前年剩余年假"+(available-useNumber)+"小时");
//            }
//        }

//        if(collect.size()>0){
//            if (preTotalNum <preSum + preUseNum) {
//                throw new Exception("你有补去年假但去年年假时长不够,去年剩余年假" + (preTotalNum - preUseNum) + "小时");
//            }
//        }

        // 只有限制时间外得数据 值判断今年结余
        if(collect1.size()>0 &&collect2.size()==0 && collect.size() == 0){
//            if (available <sum + useNumber) {
//                throw new Exception("可用年假时长不够,当前剩余年假"+(available-useNumber)+"小时");
//            }
            tbHrLeaveUseNum.setUseNum(sum + useNumber);
            tbHrLeaveHiUseNum.setUseNum(sum);
        }else if(collect1.size()==0 &&collect2.size()==0 && collect.size()> 0){  // 只有去年得数据
//            if (preTotalNum < sum + preUseNum) {
//                throw new Exception("你有补去年假但去年年假时长不够,去年剩余年假" + (preTotalNum - preUseNum) + "小时");
//            }
            tbHrLeaveUseNum.setPreUseNum(sum + preUseNum);
            tbHrLeaveHiUseNum.setPreUseNum(sum);
        }else {
//            if (preTotalNum+available < sum+useNumber+preUseNum) {
//                throw new Exception("可用年假时长不够,当前剩余年假"+((available-useNumber)+(preTotalNum-preUseNum))+"小时");
//            }
            if(collect1.size()>0){
                tbHrLeaveUseNum.setUseNum(preSum1+useNumber);
                sum = sum-preSum1;
                tbHrLeaveHiUseNum.setUseNum(preSum1);

            }
            // 去年结余大于休假时间
            if (preNum>sum) {
                tbHrLeaveUseNum.setPreUseNum(preUseNum+sum);
                tbHrLeaveHiUseNum.setPreUseNum(sum);
            }else {
                tbHrLeaveUseNum.setPreUseNum(preTotalNum);
                tbHrLeaveUseNum.setUseNum(tbHrLeaveUseNum.getUseNum()+(sum-preNum));
                tbHrLeaveHiUseNum.setUseNum(sum-preNum+preSum1);
                tbHrLeaveHiUseNum.setPreUseNum(preNum);

            }
        }
        tbHrLeaveHiUseNumMapper.insert(tbHrLeaveHiUseNum);
        tbHrLeaveUseNum.setYear(year);
        return  tbHrLeaveUseNum;
    }


    public static void main(String[] args) {

        System.err.println(50/12);
        System.err.println(50%12);

    }

    /**
     * 处理上传社保凭证
     * @author 苏小林
     * @date 2021/8/6 16:15
     * @param: apply
     * @return: com.xhsj.user.hr.process.query.ApprovalQuery
     */
    private ApprovalQuery handleSocialSecurity(TbHrApprovalLeaveApply apply) throws Exception {

        List<FirstProcessNodeIdQuery> firstProcessNodeIdQuery= processNodeMapper.firstProcessNodeId(8,apply.getOrganizationId());
        if (firstProcessNodeIdQuery.size() == 0) {
            throw new Exception("此部门下无流程节点,请联系管理员添加流程");
        }


        String roleName = roleKeyNameProperites.getXingzheng();
        Long roleId = userMapper.getRoleIdByRoleKeyName(roleName);
        if (roleId == null) {
            throw new Exception("行政助理角色不存在,请先完善角色。");
        }

        Set<String> fullNameByRoleIds = userMapper.getFullNameByRoleIds(Arrays.asList(String.valueOf(roleId)));
        if (fullNameByRoleIds.size() == 0) {
            throw new Exception("下一节点行政助理用户不存在,请联系人事！");
        }
        String handler = Joiner.on(",").join(fullNameByRoleIds);

        // 当前用户的角色id
        List<Long> roleListByUserId = tbGlobalRoleMapper.getRoleListByUserId(apply.getCreateBy());
        // 判断用户所走流程
        Long processBusinessId = this.getProcessBusinessId(firstProcessNodeIdQuery, roleListByUserId);
        TbGlobalApprovalTask tbGlobalApprovalTask = new TbGlobalApprovalTask();
        tbGlobalApprovalTask.setBusinessId(processBusinessId);
        tbGlobalApprovalTask.setDataId(apply.getId());
        tbGlobalApprovalTask.setNodeId(100L);
        tbGlobalApprovalTask.setRoleId(roleId);
        tbGlobalApprovalTask.setProposerId(UserUtils.getLoginAppUser().getUserId());
        tbGlobalApprovalTask.setHandler(handler);



        tbGlobalApprovalTaskService.startSaveCurrentRunAndHisTask(tbGlobalApprovalTask,"","请假申请",1L);

        tbGlobalApprovalTaskService.savaRunAndHisTask(tbGlobalApprovalTask,"","行政助理审核");
        TbHrApprovalLeaveApply apply_1 = new TbHrApprovalLeaveApply();
        BeanUtils.copyProperties(apply,apply_1);
        apply_1.setId(apply.getId());
        apply_1.setNodeId(100L);
        apply_1.setNodeName("行政助理审核");
        apply_1.setBusinessId(processBusinessId);
        dao.updateById(apply_1);

        // 拼接消息参数
        ApprovalQuery approvalQuery = new ApprovalQuery();
        approvalQuery.setDataId(apply.getId());
        approvalQuery.setProjectId(4);
        approvalQuery.setTitle(MessageConstant.MSG_0);
        approvalQuery.setRoleIds(Arrays.asList(roleId));
        approvalQuery.setCurrentUserId(UserUtils.getLoginAppUser().getUserId());
        approvalQuery.setCreateName(UserUtils.getLoginAppUser().getFullName());

        return approvalQuery;


    }

    // 修改可用时长
    private void updateOvertimeUsable(List<TbHrApprovalLeaveTime> tbHrApprovalLeaveTimes) throws Exception {

        List<TbHrLeaveSetting> tbHrLeaveSettings = tbHrLeaveSettingService.selectAll();
        // 请假设置
        TbHrLeaveSetting tbHrLeaveSetting = tbHrLeaveSettings.get(0);
        // 加班调休过期时间
        String overTimeExpireDate = tbHrLeaveSetting.getOverTimeExpireDate();
        // 本年份
        int currentYear = LocalDate.now().getYear();

        String str = currentYear + "-" + overTimeExpireDate;
        //指定转换格式
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        // 本年度截止日期
        LocalDate expireDate = LocalDate.parse(str, fmt);

        // 查询出本年度加班可用数
        LeaveUsableLengthVo currentUseable = tbHrLeaveUsableLengthMapper.getNumberByUserIdAndYear(String.valueOf(currentYear), UserUtils.getLoginAppUser().getUserId());
        // 查询出上年度加班可用数
        LeaveUsableLengthVo preUseable = tbHrLeaveUsableLengthMapper.getNumberByUserIdAndYear(String.valueOf(currentYear - 1), UserUtils.getLoginAppUser().getUserId());


        for (TbHrApprovalLeaveTime tbHrApprovalLeaveTime : tbHrApprovalLeaveTimes) {
            LocalDate startDate = DateUtils.date2LocalDate(tbHrApprovalLeaveTime.getStartDate());

            // 请假时间是在截止时间之前 或者请假时间等于截止时间
            if (startDate.isBefore(expireDate) || startDate.equals(expireDate)) {
                int hours = calculateHours(tbHrApprovalLeaveTime.getStartTime(), tbHrApprovalLeaveTime.getStopTime());


            }
        }


    }

    /**
     * 判断时间
     *
     * @author 苏小林
     * @date 2020/12/3 17:09
     * @param: timeList
     * @return: int
     */
    public int judgeDate(List<TbHrApprovalLeaveTime> timeList) throws Exception {
        List<TbHrLeaveSetting> tbHrLeaveSettings = tbHrLeaveSettingService.selectAll();
        // 请假设置
        TbHrLeaveSetting tbHrLeaveSetting = tbHrLeaveSettings.get(0);
        // 加班调休过期时间
        String overTimeExpireDate = tbHrLeaveSetting.getOverTimeExpireDate();
        // 本年份
        int currentYear = LocalDate.now().getYear();

        String str = currentYear + "-" + overTimeExpireDate;
        //指定转换格式
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        // 本年度截止日期
        LocalDate date = LocalDate.parse(str, fmt);

        int ff = 0; // 1 请假时间在截止时间之前 2 请假时间在截止时间之后 3 两者都有

        boolean after = false; // 请假时间在截止时间之后： true
        boolean before = false; // 请假时间在截止时间之前：true

        // 加班日期set
        Set<LocalDate> objects = Sets.newHashSet();
        for (TbHrApprovalLeaveTime tbHrApprovalLeaveTime : timeList) {
            LocalDate stopDate = DateUtils.date2LocalDate(tbHrApprovalLeaveTime.getStopDate());
            LocalDate startDate = DateUtils.date2LocalDate(tbHrApprovalLeaveTime.getStartDate());
            objects.add(startDate);
            objects.add(stopDate);
        }


        for (LocalDate localDate : objects) {

            // 请假时间是在截止时间之前 或者请假时间等于截止时间
            if (localDate.isBefore(date) || localDate.equals(date)) {
                before = true;
            }
            // 请假时间在结束时间之后
            if (localDate.isAfter(date)) {
                after = true;
            }
        }

        // 请假时间在截止时间之前
        if (before && !after) {
            ff = 1;
        }
        // 请假时间在截止时间之后
        if (!before && after) {
            ff = 2;
        }

        // 请假时间在截止时间之前和截止时间之后都有
        if (before && after) {
            ff = 3;
        }
        return ff;
    }

    /**
     * 判断加班时间是否足够
     *
     * @author 苏小林
     * @date 2020/12/3 17:06
     * @param: timeList
     * @return: int
     */
    /*public int judgeUsable(List<TbHrApprovalLeaveTime> timeList) throws Exception {
        List<TbHrLeaveSetting> tbHrLeaveSettings = tbHrLeaveSettingService.selectAll();
        // 请假设置
        TbHrLeaveSetting tbHrLeaveSetting = tbHrLeaveSettings.get(0);
        // 加班调休过期时间
        String overTimeExpireDate = tbHrLeaveSetting.getOverTimeExpireDate();
        // 本年份
        int currentYear = LocalDate.now().getYear();

        String str = currentYear + "-" + overTimeExpireDate;
        //指定转换格式
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        // 本年度截止日期
        LocalDate date = LocalDate.parse(str, fmt);

        LocalDate queryCurrentDate = null;
        LocalDate queryNextDate = null;
        int ff = 0; // 1 请假时间在截止时间之前 2 请假时间在截止时间之后 3 两者都有

        boolean after = false; // 请假时间在截止时间之后： true
        boolean before = false; // 请假时间在截止时间之前：true
        int allLength = 0; // 总调休时长

        // 加班日期set
        Set<LocalDate> objects = Sets.newHashSet();


        for (TbHrApprovalLeaveTime tbHrApprovalLeaveTime : timeList) {
            LocalDate stopDate = DateUtils.date2LocalDate(tbHrApprovalLeaveTime.getStopDate());
            LocalDate startDate = DateUtils.date2LocalDate(tbHrApprovalLeaveTime.getStartDate());
            objects.add(startDate);
            objects.add(stopDate);
            int i = tbHrApprovalLeaveTime.getDays().intValue();
            allLength += i;
        }

        for (LocalDate localDate : objects) {
            LocalDate now = LocalDate.now();

            long l = localDate.toEpochDay() - now.toEpochDay();
            if (l > 30) {
                throw new Exception("调休时间超过30天");
            }

            // 请假时间是在截止时间之前 或者请假时间等于截止时间
            if (localDate.isBefore(date) || localDate.equals(date)) {
                queryCurrentDate = date;
                before = true;
            }
            // 请假时间在结束时间之后
            if (localDate.isAfter(date)) {
                if (localDate.getYear() != date.getYear()) {
                    queryNextDate = localDate;
                } else {
                    queryNextDate = localDate;
                }
                after = true;
            }
        }

        // 请假时间在截止时间之前
        if (before && !after) {
            ff = 1;
            CompensatoryLeaveTimeQuery overTimeUsableLength = tbHrLeaveUsableLengthService.getOverTimeUsableLength(UserUtils.getLoginAppUser().getUserId(), queryCurrentDate);
            // 剩余时间小时数
            int surplusTime = overTimeUsableLength.getSurplusTime();

            if (allLength > surplusTime) {
                throw new Exception("截止到" + date.format(fmt) + ",可用小时数:" + surplusTime + "小时");
            }
        }
        // 请假时间在截止时间之后
        if (!before && after) {
            ff = 2;
            CompensatoryLeaveTimeQuery overTimeUsableLength = tbHrLeaveUsableLengthService.getOverTimeUsableLength(UserUtils.getLoginAppUser().getUserId(), queryNextDate);
            // 剩余时间小时数
            int surplusTime = overTimeUsableLength.getSurplusTime();

            if (allLength > surplusTime) {
                throw new Exception("本年度加班数量不足,可用小时数:" + surplusTime + "小时");
            }
        }

        // 请假时间在截止时间之前和截止时间之后都有
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        if (before && after) {
            ff = 3;

            int beforeNumber = 0;
            int afterNumber = 0;
            for (TbHrApprovalLeaveTime data : timeList) {
                LocalDate startDate = DateUtils.date2LocalDate(data.getStartDate());
                LocalDate stopDate = DateUtils.date2LocalDate(data.getStopDate());
                String startTime = data.getStartTime();
                String stopTime = data.getStopTime();

                //指定转换格式

                String start = startDate.format(dateTimeFormatter) + " " + startTime + ":00";
                String stop = stopDate.format(dateTimeFormatter) + " " + stopTime + ":00";

                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date startParse = simpleDateFormat.parse(start);
                Date stopParse = simpleDateFormat.parse(stop);


                if (data.getStartDate().equals(data.getStopDate())) { // 两个时间相同
                    // 请假时间在截止时间之前
                    BigDecimal dayCoincidence = MyDateUtil.getDayCoincidence(startParse, stopParse, startParse, stopParse);
                    if (startDate.isBefore(date) || startDate.equals(date)) {
                        beforeNumber += dayCoincidence.intValue();
                    } else {
                        afterNumber += dayCoincidence.intValue();
                    }
                } else {
                    // 请假时间在截止时间之前
                    if (stopDate.isBefore(date) || stopDate.equals(date)) {
                        BigDecimal dayCoincidence = MyDateUtil.getDayCoincidence(startParse, stopParse, startParse, stopParse);
                        beforeNumber += dayCoincidence.intValue();
                    } else {
                        if (startDate.isBefore(date) || startDate.equals(date)) {
                            String stop_1 = date.format(dateTimeFormatter) + " " + "09:00:00";
                            Date stopParse_1 = simpleDateFormat.parse(stop_1);
                            BigDecimal dayCoincidence = MyDateUtil.getDayCoincidence(stopParse_1, stopParse, stopParse_1, stopParse);
                            afterNumber += dayCoincidence.intValue();
                            beforeNumber += data.getDays().intValue() - dayCoincidence.intValue();
                        } else {
                            BigDecimal dayCoincidence = MyDateUtil.getDayCoincidence(startParse, stopParse, startParse, stopParse);
                            afterNumber += dayCoincidence.intValue();
                        }
                    }
                }
            }

            // 查询上一年和本年度加班可用数
            CompensatoryLeaveTimeQuery overTimeUsableLength = tbHrLeaveUsableLengthService.getOverTimeUsableLength(UserUtils.getLoginAppUser().getUserId(), date);
            if (overTimeUsableLength.getSurplusTime() < beforeNumber) {
                throw new Exception(date.format(dateTimeFormatter) + "前可用时长小于您请假时长");
            } else {
                int num_1 = overTimeUsableLength.getSurplusTime() - beforeNumber;
                if (num_1 < afterNumber) {
                    throw new Exception(date.format(dateTimeFormatter) + "后可用时长小于您请假时长");
                }
            }

        }
        return ff;
    }*/

    /**
     * 流程-hr请假时间表
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    public void saveTbHrApprovalLeaveTime(List<TbHrApprovalLeaveTime> timeList, TbHrApprovalLeaveApply apply) throws Exception {

        boolean b = tbHrApprovalLeaveTimeService.saveBatch(timeList);
        if (!b) {
            throw new Exception("保存流程-hr请假时间表异常");
        }

    }

    /**
     * 拆分日期 - 请假时间一条记录大于一天的拆分成一天一条数据
     *
     * @author 苏小林
     * @date 2021/6/8 9:53
     * @param: timeList
     * @param: apply
     * @return: java.util.List<com.xhsj.user.hr.process.hrLeaveProcess.entity.TbHrApprovalLeaveTime>
     */
    private List<TbHrApprovalLeaveTime> splitDate(List<TbHrApprovalLeaveTime> timeList, TbHrApprovalLeaveApply apply) throws Exception {
        List<TbHrApprovalLeaveTime> allList = Lists.newArrayList();
        // 流程-hr请假时间表
        for (TbHrApprovalLeaveTime time : timeList) {

            Date startDate = time.getStartDate();
            Date stopDate = time.getStopDate();
            if (!startDate.equals(stopDate)) {
                // 获取两个日期之间的天数
                int distanceOfTwoDate = DateUtils.getDistanceOfTwoDate(startDate, stopDate);
                for (int i = 0; i <= distanceOfTwoDate; i++) {
                    TbHrApprovalLeaveTime leaveTime = new TbHrApprovalLeaveTime();
                    leaveTime.setId(null);
                    leaveTime.setOperationType(0);
                    leaveTime.setDataId(apply.getId());
                    leaveTime.setCreateBy(UserUtils.getLoginAppUser().getUserId());
                    leaveTime.setUpdateBy(UserUtils.getLoginAppUser().getUserId());
                    leaveTime.setCreateDate(new Date());
                    leaveTime.setUpdateDate(new Date());
                    if (i == 0) {
                        leaveTime.setStartDate(time.getStartDate());
                        leaveTime.setStartTime(time.getStartTime());
                        leaveTime.setStopDate(time.getStartDate());
                        leaveTime.setStopTime("18:00");
                        int hours = calculateHours(time.getStartTime(), "18:00");
                        leaveTime.setDays(new BigDecimal(hours));
                    } else if (i == distanceOfTwoDate) {
                        leaveTime.setStartDate(time.getStopDate());
                        leaveTime.setStartTime("09:00");
                        leaveTime.setStopDate(time.getStopDate());
                        leaveTime.setStopTime(time.getStopTime());
                        int hours = calculateHours("09:00", time.getStopTime());
                        leaveTime.setDays(new BigDecimal(hours));
                    } else {
                        Date date = DateUtils.addDays(time.getStartDate(), i, Date.class);
                        leaveTime.setStartDate(date);
                        leaveTime.setStartTime("09:00");
                        leaveTime.setStopDate(date);
                        leaveTime.setStopTime("18:00");
                        leaveTime.setDays(new BigDecimal(8));
                    }
                    if (apply.getVacationId() == 12) {
                        splitDate_1(allList, leaveTime);
                    } else {
                        allList.add(leaveTime);
                    }

                }

            } else {
                time.setId(null);
                time.setOperationType(0);
                time.setDataId(apply.getId());
                time.setCreateBy(apply.getCreateBy());
                time.setCreateDate(new Date());
                time.setUpdateDate(new Date());

                if (apply.getVacationId() == 12) {
                    splitDate_1(allList, time);
                } else {
                    allList.add(time);
                }
            }
        }
        System.err.println(allList);
        return allList;
    }

    /**
     * @Description: 计算年假 拆分后时间
     * @Param:
     * @return:
     * @Author: liuqinghua
     * @Date: 2021/11/3
     */
    private int calculateAnnualLeaveHours(String startTime, String stopTime) {
        if("1".equals(startTime) && "1".equals(stopTime))
            return 4;
        if("1".equals(startTime) && "2".equals(stopTime))
            return 8;
        if("2".equals(startTime) && "2".equals(stopTime))
            return 4;
        return 0;
    }

    /**
     * 拆分请假时间 - 针对 调休时长 小于 上年度可用加班时长
     *
     * @author 苏小林
     * @date 2021/6/8 16:02
     * @param: allList
     * @param: leaveTime
     */
    private void splitDate_1(List<TbHrApprovalLeaveTime> allList, TbHrApprovalLeaveTime leaveTime) throws Exception {
        // 判断 请假时间 是否在 截止时间之前
        List<TbHrLeaveSetting> tbHrLeaveSettings = tbHrLeaveSettingService.selectAll();
        // 请假设置
        TbHrLeaveSetting tbHrLeaveSetting = tbHrLeaveSettings.get(0);
        // 加班调休过期时间
        String overTimeExpireDate = tbHrLeaveSetting.getOverTimeExpireDate();
        // 本年份
        int currentYear = LocalDate.now().getYear();

        String str = currentYear + "-" + overTimeExpireDate;
        //指定转换格式
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        // 本年度截止日期
        LocalDate expireDate = LocalDate.parse(str, fmt);
        int lastYearOccupy = 0; // 上一年占用数
        int currentYearOccupy = 0; // 本年占用数

        // 查询出上年度加班可用数
        LeaveUsableLengthVo preUseable = tbHrLeaveUsableLengthMapper.getNumberByUserIdAndYear(String.valueOf(currentYear - 1), UserUtils.getLoginAppUser().getUserId());

        // 上年度加班可用时长大于0 并且 请假时间是在截止时间之前 或者请假时间等于截止时间
        if (preUseable.getOverTimeUsable() > 0 && (DateUtils.date2LocalDate(leaveTime.getStartDate()).isBefore(expireDate) || DateUtils.date2LocalDate(leaveTime.getStartDate()).equals(expireDate))) {
            // 计算请假时长
            int hours = calculateHours(leaveTime.getStartTime(), leaveTime.getStopTime());
            // 请假时长 大于 上年度剩余可用时长
            if (hours >= preUseable.getOverTimeUsable()) {
                // 使用上一年的加班时长
                TbHrApprovalLeaveTime leaveTime_ = new TbHrApprovalLeaveTime();
                BeanUtils.copyProperties(leaveTime, leaveTime_);

                String[] split = leaveTime_.getStartTime().split(":");
                // 结束时间
                int stp = Integer.valueOf(split[0]) + preUseable.getOverTimeUsable();
                if (Integer.valueOf(split[0]) <= 12 && stp >= 13) {
                    stp = stp + 1;
                }


                String stp_ = stp + ":00";
                leaveTime_.setStopTime(stp_);
                leaveTime_.setDays(new BigDecimal(preUseable.getOverTimeUsable()));
                leaveTime_.setOccupyYear(String.valueOf(currentYear - 1));
                allList.add(leaveTime_);
                lastYearOccupy += preUseable.getOverTimeUsable();

                // 使用本年度的加班时长
                TbHrApprovalLeaveTime leaveTime_1 = new TbHrApprovalLeaveTime();
                BeanUtils.copyProperties(leaveTime, leaveTime_1);
                leaveTime_1.setStartTime(leaveTime_.getStopTime());
                leaveTime_1.setDays(new BigDecimal(hours - preUseable.getOverTimeUsable()));
                leaveTime_1.setOccupyYear(String.valueOf(currentYear));
                if (!leaveTime_1.getStartTime().equals(leaveTime_1.getStopTime())) {
                    allList.add(leaveTime_1);
                    currentYearOccupy += (hours - preUseable.getOverTimeUsable());
                }

            } else {
                int hours_ = calculateHours(leaveTime.getStartTime(), leaveTime.getStopTime());
                leaveTime.setDays(new BigDecimal(hours_));
                leaveTime.setOccupyYear(String.valueOf(currentYear - 1));
                allList.add(leaveTime);
                lastYearOccupy += hours_;
            }
        } else {
            int hours = calculateHours(leaveTime.getStartTime(), leaveTime.getStopTime());
            leaveTime.setDays(new BigDecimal(hours));
            leaveTime.setOccupyYear(String.valueOf(currentYear));
            currentYearOccupy += hours;
            allList.add(leaveTime);
        }

        // 修改本年和上一年的加班占用数
        tbHrLeaveUsableLengthMapper.substractNumberByUserIdAndYear(String.valueOf(currentYear), UserUtils.getLoginAppUser().getUserId(), currentYearOccupy);
        tbHrLeaveUsableLengthMapper.substractNumberByUserIdAndYear(String.valueOf(currentYear - 1), UserUtils.getLoginAppUser().getUserId(), lastYearOccupy);
    }

    private int calculateHours(String startTime, String stopTime) throws Exception {
        String[] split = startTime.split(":");
        String[] split1 = stopTime.split(":");
        int start = Integer.parseInt(split[0]);
        int end = Integer.parseInt(split1[0]);
        if (end < start) {
            throw new Exception("结束时间不能小于开始时间");
        }

        if (start <= 12 && end <= 12) {
            return end - start;
        }

        if (start <= 12 && end <= 18) {
            return end - start - 1;
        }

        if (start >= 13 && end <= 18) {
            return end - start;
        }

        return 0;

    }

    /**
     * 执行开始请假流程启动
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    public ApprovalQuery startLeaveApplyRun(TbHrApprovalLeaveApply apply) throws Exception {
        HandleAuditDto handleAuditDto = new HandleAuditDto();
        handleAuditDto.setDataId(apply.getId());
        handleAuditDto.setProposerId(apply.getCreateBy());
        handleAuditDto.setCreateBy(apply.getCreateBy());
        handleAuditDto.setApplyType(8);
        // 执行流程
        ProcessNodeQuery processNodeQuery = tbGlobalApprovalTaskService.startHandleAudit(handleAuditDto, apply.getOrganizationId());
        // 修改产品申请表节点名称和节点id
        return updateHrApprovalLeaveApply(handleAuditDto, processNodeQuery);
    }

    // 修改节点id和节点名称请假申请
    public ApprovalQuery updateHrApprovalLeaveApply(HandleAuditDto data, ProcessNodeQuery processNodeQuery) throws Exception {
        //修改产品申请表节点名称和节点id
        TbHrApprovalLeaveApply tbHrApprovalLeaveApply = new TbHrApprovalLeaveApply();
        tbHrApprovalLeaveApply.setId(data.getDataId());
        tbHrApprovalLeaveApply.setNodeName(processNodeQuery.getNodeName());
        tbHrApprovalLeaveApply.setNodeId(processNodeQuery.getNodeId());
        tbHrApprovalLeaveApply.setUpdateBy(data.getCreateBy());
        tbHrApprovalLeaveApply.setUpdateDate(data.getCreateDate());
        tbHrApprovalLeaveApply.setBusinessId(data.getBusinessId());
        tbHrApprovalLeaveApply.setDelFlag(processNodeQuery.getDelFlag());
        if (!this.save(tbHrApprovalLeaveApply)) {
            throw new Exception("修改请假申请节点名称信息异常");
        }

        String fullName = dao.getFullNameByDataId(data.getDataId(),"tb_hr_approval_leave_apply");

        // 消息参数
        return tbHrApprovalBecomeRegularApplyService.setApprovalQuery(data.getDataId(),
                4, MessageConstant.MSG_0, processNodeQuery,fullName);
    }

    // 获取流程BusinessId
    public Long getProcessBusinessId (List<FirstProcessNodeIdQuery> firstProcessNodeIdQuery, List<Long> roleListByUserId){
        for (FirstProcessNodeIdQuery firstProcessNodeId :firstProcessNodeIdQuery) {
            if (roleListByUserId.contains(firstProcessNodeId.getRoleId())) {
                return firstProcessNodeId.getBusinessId();
            }
            if (StringUtils.isNull(firstProcessNodeId.getRoleId())) {
                return firstProcessNodeId.getBusinessId();
            }
        }
        return null;
    }

    /**
     * 我的请假申请
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    public Page<MyLeaveApplyListQuery> myLeaveApplyList(MyLeaveApplyListDto data) {
        LoginUser loginAppUser = UserUtils.getLoginAppUser();
        Long userId = loginAppUser.getUserId();
        Page<MyLeaveApplyListQuery> page = new Page(data.getPage(), data.getSize());
        return dao.myLeaveApplyList(page, userId, data);
    }

    /**
     * 待审核请假申请列表
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    public Page<RunLeaveApplyListQuery> runLeaveApplyList(RunLeaveApplyListDto data) {
        Page<MyLeaveApplyListQuery> page = new Page(data.getPage(), data.getSize());
        Long userId = data.getUserId();
        // 获取用户角色id
        List<Long> roleByUserId = tbGlobalRoleMapper.getRoleListByUserId(userId);
        return dao.runLeaveApplyList(page, roleByUserId, userId, data);
    }

    /**
     * 已审核请假申请列表
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    public Page<CompletedLeaveApplyList> completedLeaveApplyList(RunLeaveApplyListDto data) {
        Page<CompletedLeaveApplyList> page = new Page(data.getPage(), data.getSize());
        Long userId = data.getUserId();
        return dao.completedLeaveApplyList(page, userId, data);
    }

    /**
     * 我的请假申请详细信息
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    public MyLeaveApplyDetailedListQuery myLeaveApplyDetailedList(Long dataId, Long businessId, Integer operationType) {
        MyLeaveApplyDetailedListQuery myLeaveApplyDetailedListQuery = new MyLeaveApplyDetailedListQuery();
        // 请假申请基本信息
        LeaveApplyBaseQuery leaveApplyBaseList = dao.getLeaveApplyBaseList(dataId);
        // 请假原因和延期原因
        if (leaveApplyBaseList != null) {
            // 请假申请时间
            List<Long> dataIdList = new ArrayList<>();
            dataIdList.add(dataId);
            List<LeaveTimeQuery> leaveTimeList = tbHrApprovalLeaveTimeService.getLeaveTimeList(dataIdList, businessId);

            log.debug("operationType------" + operationType);
            myLeaveApplyDetailedListQuery.setTimeList(leaveTimeList);

            // 审批意见
            List<ApprovalHiTaskQuery> approvalHiTaskList = tbGlobalApprovalHiTaskService.getApprovalHiTaskList(dataId, businessId);
            myLeaveApplyDetailedListQuery.setCommentList(approvalHiTaskList);

            // 流程节点
            List<WorkFlowNodeQuery> workFlowNodeQueries = tbGlobalWorkFlowNodeService.nodeList(businessId);
            myLeaveApplyDetailedListQuery.setApply(leaveApplyBaseList);

            myLeaveApplyDetailedListQuery.setNodeList(workFlowNodeQueries);

        }
        return myLeaveApplyDetailedListQuery;
    }

    /**
     * 已调休,加班时间，剩余调休时间
     */
    public CompensatoryLeaveTimeQuery getCompensatoryLeaveTime() {
        CompensatoryLeaveTimeQuery compensatoryLeaveTimeQuery = new CompensatoryLeaveTimeQuery();
        // 获取加班的总时长
        LoginUser loginAppUser = UserUtils.getLoginAppUser();
        int hrOvertime = tbHrOvertimeApplyMapper.getHrOvertime(loginAppUser.getUserId());
        // 获取已调休总时长
        int compensatoryLeaveTime = dao.getCompensatoryLeaveTime(loginAppUser.getUserId(), 12);
        // 获取已销假的总时长
        int cancellationLeaveTime = dao.getCancellationLeaveTime(loginAppUser.getUserId(), 12);
        compensatoryLeaveTime = compensatoryLeaveTime - cancellationLeaveTime;
        // 剩余时长
        int surplusTime = hrOvertime - compensatoryLeaveTime;
        compensatoryLeaveTimeQuery.setHrOvertime(hrOvertime);
        compensatoryLeaveTimeQuery.setCompensatoryLeaveTime(compensatoryLeaveTime);
        compensatoryLeaveTimeQuery.setSurplusTime(surplusTime);
        return compensatoryLeaveTimeQuery;
    }

    /**
     * 请假流程审批
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    public ApprovalQuery approvalLeaveApply(HandleAuditDto data) throws Exception {

        Long businessId = data.getBusinessId();
        Long nodeId = data.getNodeId();

        TbHrApprovalLeaveApply byId = this.getById(data.getDataId());
        if (byId.getNodeId() == 100 && byId.getVacationId() ==3) { // 代表是第一次年假  上传社保凭证
            // 社保凭证审核
            return handleAuditSocialSecurity(data,byId);
        }

        Map<String, Object> map = tbGlobalApprovalTaskMapper.getJudge(businessId, nodeId + 1);

        String judge = StringUtils.getStringValue(map, "judge");
        if (StringUtils.isNotBlank(judge)) { // 如果不为空
            int jud = Integer.parseInt(judge);// 判断条件
            BigDecimal days = byId.getDays();

            BigDecimal b2 = new BigDecimal(String.valueOf(days));
            BigDecimal b1 = new BigDecimal(String.valueOf(jud * 8));
            int i = b2.compareTo(b1);
            if (i < 1) { // 请假天数小于约定天数
                data.setNodeId(nodeId + 1);
            }
        }

        // 执行流程
        ProcessNodeQuery processNodeVo = tbGlobalApprovalTaskService.handleAudit(data);

        Integer status = data.getStatus();
        if (status == 1) { // 驳回
            handleReject(data, byId);
        }

        if ("完结".equals(processNodeVo.getNodeName())) {
            handleEndProcess(data, byId);

            if (byId.getVacationId()  == 3) { // 年假
                tbHrLeaveHiUseNumMapper.deleteByDataId(byId.getId());
            }
        }
        // 修改产品申请表节点名称和节点id
        return updateHrApprovalLeaveApply(data, processNodeVo);
    }

    private ApprovalQuery handleAuditSocialSecurity(HandleAuditDto data,TbHrApprovalLeaveApply apply) throws Exception {
        tbGlobalApprovalTaskService.delById(data.getProcessTaskId());

        TbGlobalApprovalHiTask hiTask = new TbGlobalApprovalHiTask();
        hiTask.setId(data.getProcessTaskId());
        hiTask.setUserId(UserUtils.getLoginAppUser().getUserId());
        hiTask.setHandler(UserUtils.getLoginAppUser().getFullName());
        hiTask.setStatus(data.getStatus());
        hiTask.setOpinionText(data.getOpinionText());

        tbGlobalApprovalHiTaskMapper.updateHiTask(hiTask);

        TbHrUserSocialSecurity userSocialSecurity = tbHrUserSocialSecurityService.getUserSocialSecurity(data.getProposerId(), apply.getId());
        if (data.getStatus() ==0) { // 审核通过

            if (userSocialSecurity.getConfirmDate() == null) {
                throw new Exception("请先确认工龄");
            }

            // 校验年假可用数

            int available = userSocialSecurity.getTotalNumber();
            int useNumber = userSocialSecurity.getUseNumber();

            // 请假
            QueryWrapper<TbHrApprovalLeaveTime> queryWrapper= new QueryWrapper();
            queryWrapper.eq("del_flag",0);
            queryWrapper.eq("data_id",apply.getId());
            List<TbHrApprovalLeaveTime> tbHrApprovalLeaveTime = tbHrApprovalLeaveTimeMapper.selectList(queryWrapper);
            // 检验
            TbHrLeaveUseNum tbHrLeaveUseNum = checkTiem(tbHrApprovalLeaveTime, userSocialSecurity);
            if(tbHrLeaveUseNum.getId() != null){
                int i = tbHrLeaveUseNumMapper.updateById(tbHrLeaveUseNum);
                if(i != 1){
                    throw new Exception("修改年假已休表异常");
                }
            }else{
                // 修改今年年假已用时长和去年年假已用时长根据id
                tbHrLeaveUseNum.setSocialSecurityId(userSocialSecurity.getId());
                if( tbHrLeaveUseNumMapper.insert(tbHrLeaveUseNum) != 1){
                    throw new Exception("修改年假已休表异常");
                }
            }
            // 修改年假已用时长  - 临时用  后面不用这个接口
//            tbHrUserSocialSecurityService.updateUseNum(userSocialSecurity.getId(),sum);


            return this.startLeaveApplyRun(apply);
        } else {

            if (userSocialSecurity.getConfirmDate() == null) {
                tbHrUserSocialSecurityService.delByUserId(data.getProposerId());
            }

            // 行政助理审核退回 申请人
            TbGlobalApprovalTask tbGlobalApprovalTask = new TbGlobalApprovalTask();
            tbGlobalApprovalTask.setBusinessId(data.getBusinessId());
            tbGlobalApprovalTask.setDataId(apply.getId());
            tbGlobalApprovalTask.setNodeId(1L);
            tbGlobalApprovalTask.setUserId(data.getProposerId());
            tbGlobalApprovalTask.setProposerId(UserUtils.getLoginAppUser().getUserId());

            tbGlobalApprovalTaskService.savaRunAndHisTask(tbGlobalApprovalTask,data.getOpinionText(),"申请人修改");

            TbHrApprovalLeaveApply apply_1 = new TbHrApprovalLeaveApply();
            apply_1.setId(apply.getId());
            apply_1.setNodeId(1L);
            apply_1.setNodeName("申请人修改");
            apply_1.setBusinessId(data.getBusinessId());
            dao.updateById(apply_1);


            // 拼接消息参数
            ApprovalQuery approvalQuery = new ApprovalQuery();
            approvalQuery.setDataId(apply.getId());
            approvalQuery.setProjectId(4);
            approvalQuery.setTitle(MessageConstant.MSG_0);
            approvalQuery.setUserId(Arrays.asList(data.getProposerId()));
            approvalQuery.setCurrentUserId(UserUtils.getLoginAppUser().getUserId());
            approvalQuery.setCreateName(UserUtils.getLoginAppUser().getFullName());
            return approvalQuery;
        }

    }

    /***
     * 计算剩余年假数
     * @author 苏小林
     * @date 2021/8/10 15:07
     * @param: year
     * @param: userId
     * @param: dataId 用作查询用户年度年假使用数量 如果为空 表示查询全部  不为空表示 排除此id 的数据
     * @return: int
     */
    public String availableAnnualLeave(TbHrUserSocialSecurity tbHrUserSocialSecurity, Long userId, Long dataId) throws Exception {

        Integer year = tbHrUserSocialSecurity.getCurrentWorkingYears();
        int annualLeaveLength = 0;
        if (year >= 1 && year < 10) { // 0-10年 5天
            annualLeaveLength = 5;
        }
        if (year>=10 && year <20) { // 10-20年 10天
            annualLeaveLength = 10;
        }
        if (year >=20) { // 20年以上 15天
            annualLeaveLength = 15;
        }

        // 查询本年度已休年假小时数
        LocalDate now = LocalDate.now();
        int currentYear = now.getYear();
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        int useNumber =0; // 已使用数量
        // 暂时不用这个逻辑  - 以后用的时候再放开
        /*if (currentYear == 2021) {
            //指定转换格式
            // 本年度截止日期
            LocalDate date = LocalDate.parse("2021-04-01", fmt);
            useNumber = dao.getAnnualLeaveUseNumber(date,userId,dataId);
        } else {
            LocalDate date = LocalDate.parse(currentYear+"-01-01", fmt);
            useNumber = dao.getAnnualLeaveUseNumber(date,userId,dataId);
        }*/

        useNumber = tbHrUserSocialSecurity.getUseNum();

        // 查询入职时间  并计算 可休年假天数

        String arrivalDate = tbHrApprovalEntryApplyMapper.getArrivalDateByUserId(userId);
        if (StringUtils.isBlank(arrivalDate)) {
            throw new Exception("入职时间为空");
        }
        LocalDate arrival_Date = LocalDate.parse(arrivalDate, fmt);
        LocalDate localDate = LocalDate.now();


        Long until = null;
        if (arrival_Date.getYear() == localDate.getYear()) { // 如果是本年度入职
            until = arrival_Date.until(localDate, ChronoUnit.DAYS);
        } else {
            arrival_Date = LocalDate.parse(currentYear+"-01-01", fmt);
            until = arrival_Date.until(localDate, ChronoUnit.DAYS);
        }

        String div = StringUtils.div(until, 365, 2);
        // 可用年假小时数
        String avail_able = StringUtils.mul(div, annualLeaveLength * 8,0);

        // 可用年假小时数
        int available = Integer.parseInt(avail_able);

        return available+"&"+useNumber;

//        return available-useNumber;
    }


    private void handleReject(HandleAuditDto data, TbHrApprovalLeaveApply byId) throws Exception {
        Integer vacationId = byId.getVacationId();
        Long oldId = byId.getOldId();
        if (StringUtils.isNotBlank(oldId) && oldId != 0) { // 销假
            handleRollBackApplyTime(byId);
        } else {

            if (vacationId == 12) { // 调休驳回时 还原之前加班可用数
                QueryWrapper<TbHrApprovalLeaveTime> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("data_id", data.getDataId());
                List<TbHrApprovalLeaveTime> list = tbHrApprovalLeaveTimeService.list(queryWrapper);

                // 本年份
                int currentYear = LocalDate.now().getYear();
                int lastYearOccupy = 0; // 上一年占用数
                int currentYearOccupy = 0; // 本年占用数
                for (TbHrApprovalLeaveTime tbHrApprovalLeaveTime : list) {
                    if (String.valueOf(currentYear).equals(tbHrApprovalLeaveTime.getOccupyYear())) {
                        currentYearOccupy += tbHrApprovalLeaveTime.getDays().intValue();
                    }

                    if (String.valueOf(currentYear - 1).equals(tbHrApprovalLeaveTime.getOccupyYear())) {
                        lastYearOccupy += tbHrApprovalLeaveTime.getDays().intValue();
                    }
                }

                // 还原本年和上一年的加班占用数
                tbHrLeaveUsableLengthMapper.addOverTimeUsable(String.valueOf(currentYear), data.getProposerId(), currentYearOccupy);
                tbHrLeaveUsableLengthMapper.addOverTimeUsable(String.valueOf(currentYear - 1), data.getProposerId(), lastYearOccupy);
            }

            // 临时用 - 以后不用
            if (vacationId == 3) { // 年假

                // 修改年假已用时长  - 临时用  后面不用这个接口
                TbHrUserSocialSecurity userSocialSecurity = tbHrUserSocialSecurityService.getUserSocialSecurity(data.getProposerId(), null);
                TbHrLeaveHiUseNum tbHrLeaveHiUseNum = tbHrLeaveHiUseNumMapper.selectByDataId(byId.getId());
                // 获取去年的请假时间和去年已休时间
                int year = LocalDate.now().getYear();
                QueryWrapper<TbHrLeaveUseNum> queryWrapper2 = new QueryWrapper<>();
                queryWrapper2.eq("social_security_id",userSocialSecurity.getId());
                queryWrapper2.eq("year",year);
                TbHrLeaveUseNum tbHrLeaveUseNum = tbHrLeaveUseNumMapper.selectOne(queryWrapper2);
                tbHrLeaveUseNum.setPreUseNum(tbHrLeaveUseNum.getPreUseNum()-tbHrLeaveHiUseNum.getPreUseNum());
                tbHrLeaveUseNum.setUseNum(tbHrLeaveUseNum.getUseNum()-tbHrLeaveHiUseNum.getUseNum());
//                tbHrLeaveUseNum.setUseNum(tbHrLeaveUseNum.getHiUseNum()>0?tbHrLeaveUseNum.getHiUseNum():0);
                if(tbHrLeaveUseNum.getId() != null){
                    if(tbHrLeaveUseNumMapper.updateById(tbHrLeaveUseNum) != 1){
                        throw new Exception("修改年假已休表异常");
                    }
                }else{
                    // 修改今年年假已用时长和去年年假已用时长根据id
                    tbHrLeaveUseNum.setSocialSecurityId(userSocialSecurity.getId());
                    if( tbHrLeaveUseNumMapper.insert(tbHrLeaveUseNum) != 1){
                        throw new Exception("修改年假已休表异常");
                    }
                }
                tbHrLeaveHiUseNumMapper.deleteByDataId(byId.getId());
            }




        }
    }

    private void handleEndProcess(HandleAuditDto data, TbHrApprovalLeaveApply byId) throws Exception {
        if (StringUtils.isNotBlank(byId.getOldId()) && byId.getOldId() != 0) { // 表示销假数据
            // 本年份
            int currentYear = LocalDate.now().getYear();

            // 查询销假后的请假时间
            List<LeaveTimeVo> leaveTimeList = tbHrApprovalLeaveTimeMapper.findListByIdAndBusinessId(byId.getId(), byId.getBusinessId());
            int afterLastYearHours = 0;
            int afterCurrentYearHours = 0;
            for (LeaveTimeVo leaveTimeVo : leaveTimeList) {
                if (String.valueOf(currentYear).equals(leaveTimeVo.getOccupyYear())) {
                    afterCurrentYearHours += leaveTimeVo.getHours();
                }

                if (String.valueOf(currentYear - 1).equals(leaveTimeVo.getOccupyYear())) {
                    afterLastYearHours += leaveTimeVo.getHours();
                }
            }
            // 销假后的时长
            int n_days = leaveTimeList == null ? 0 : (int) leaveTimeList.stream().mapToInt(n -> n.getHours()).summaryStatistics().getSum();
            // 修改销假总时长数据
            TbHrApprovalLeaveApply tbHrApprovalLeaveApply = new TbHrApprovalLeaveApply();
            tbHrApprovalLeaveApply.setId(data.getDataId());
            tbHrApprovalLeaveApply.setDays(new BigDecimal(n_days));
            dao.updateById(tbHrApprovalLeaveApply);

            if (byId.getVacationId() == 12) { // 调休
                int beforeLastYearHours = 0;
                int beforeCurrentYearHours = 0;
                // 查询销假前的数据
                List<LeaveTimeVo> leaveTimeVoList = tbHrApprovalLeaveHistoryTimeMapper.findListById(byId.getOldId());
                for (LeaveTimeVo leaveTimeVo : leaveTimeVoList) {
                    if (String.valueOf(currentYear).equals(leaveTimeVo.getOccupyYear())) {
                        beforeCurrentYearHours += leaveTimeVo.getHours();
                    }

                    if (String.valueOf(currentYear - 1).equals(leaveTimeVo.getOccupyYear())) {
                        beforeLastYearHours += leaveTimeVo.getHours();
                    }
                }

                if (beforeLastYearHours - afterLastYearHours > 0) {
                    tbHrLeaveUsableLengthMapper.addOverTimeUsable(String.valueOf(currentYear - 1), data.getProposerId(), beforeLastYearHours - afterLastYearHours);
                }
                if (beforeCurrentYearHours - afterCurrentYearHours > 0) {
                    tbHrLeaveUsableLengthMapper.addOverTimeUsable(String.valueOf(currentYear), data.getProposerId(), beforeCurrentYearHours - afterCurrentYearHours);
                }

            }

            if (byId.getVacationId() == 3) { // 年假


                List<LeaveTimeVo> leaveTimeVoList = tbHrApprovalLeaveHistoryTimeMapper.findListById(byId.getOldId());
                int sum = leaveTimeVoList.stream().mapToInt(item -> item.getHours().intValue()).sum();
                TbHrUserSocialSecurity userSocialSecurity = tbHrUserSocialSecurityService.getUserSocialSecurity(data.getProposerId(), null);

                // 修改年假已用时长  - 临时用  后面不用这个接口
                tbHrUserSocialSecurityService.updateUseNum(userSocialSecurity.getId(),-(sum+n_days));

            }
        }
    }

    /***
     * 销假驳回 回滚数据
     * @author 苏小林
     * @date 2021/6/2 10:56
     * @param: byId
     */
    private void handleRollBackApplyTime(TbHrApprovalLeaveApply byId) throws Exception {

        /*回滚数据
         * 1、删除当前销假的时间段，将请假前的原时间段数据恢复
         *
         * */

        Long oldId = byId.getOldId();

        // 历史数据
        List<AllLeaveTimeListByLeaveDateQuery> allLeaveTimeList = tbHrApprovalLeaveHistoryTimeMapper.myOriginalLeaveApplyList(oldId);

        // 删除 请假时间
        tbHrApprovalLeaveTimeService.deleteByDataId(byId.getId());

        // 恢复之前的数据
        for (AllLeaveTimeListByLeaveDateQuery allLeaveTimeListByLeaveDateQuery : allLeaveTimeList) {
            TbHrApprovalLeaveTime tbHrApprovalLeaveTime = new TbHrApprovalLeaveTime();
            BeanUtils.copyProperties(allLeaveTimeListByLeaveDateQuery, tbHrApprovalLeaveTime);
            tbHrApprovalLeaveTime.setDataId(byId.getId());
            tbHrApprovalLeaveTimeService.save(tbHrApprovalLeaveTime);
        }

        // 请假时长  小时
        int days = allLeaveTimeList ==null?0:(int) allLeaveTimeList.stream().mapToInt(n -> n.getDays().intValue()).summaryStatistics().getSum();
        byId.setDays(new BigDecimal(days));
        super.save(byId);
    }

    /**
     * @author 苏小林
     * @date 2020/10/28 17:50
     * @param: timeList
     * @param: f_flag 1 请假时间在截止时间之前 2 请假时间在截止时间之后 3 两者都有
     */
    /*public void substractOvertimeUsable(List<TbHrApprovalLeaveTime> timeList, int f_flag) throws ParseException {
        List<TbHrLeaveSetting> tbHrLeaveSettings = tbHrLeaveSettingService.selectAll();
        // 请假设置
        TbHrLeaveSetting tbHrLeaveSetting = tbHrLeaveSettings.get(0);
        // 加班调休过期时间
        String overTimeExpireDate = tbHrLeaveSetting.getOverTimeExpireDate();
        // 本年份
        int currentYear = LocalDate.now().getYear();

        String str = currentYear + "-" + overTimeExpireDate;
        //指定转换格式
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        // 本年度截止日期
        LocalDate date = LocalDate.parse(str, fmt);

        // 下年度截止日期
        LocalDate nextDate = date.minusYears(1);


        // 查询是否有本年度数据
        QueryWrapper<TbHrLeaveUsableLength> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("year", String.valueOf(currentYear));
        queryWrapper.eq("create_by", UserUtils.getLoginAppUser().getUserId());
        Integer integer = tbHrLeaveUsableLengthMapper.selectCount(queryWrapper);
        if (integer == null || integer == 0) {
            TbHrLeaveUsableLength tbHrLeaveUsableLength = new TbHrLeaveUsableLength();
            tbHrLeaveUsableLength.setCreateBy(UserUtils.getLoginAppUser().getUserId());
            tbHrLeaveUsableLength.setYear(String.valueOf(currentYear));
            tbHrLeaveUsableLength.setAllOverTime(0);
            tbHrLeaveUsableLength.setOverTimeUsable(0);
            tbHrLeaveUsableLength.setAnnualLeaveUsable(0);
            tbHrLeaveUsableLengthMapper.insert(tbHrLeaveUsableLength);
        }

        // 查询是否有上年度数据
        QueryWrapper<TbHrLeaveUsableLength> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("year", String.valueOf(currentYear - 1));
        queryWrapper1.eq("create_by", UserUtils.getLoginAppUser().getUserId());
        Integer integer1 = tbHrLeaveUsableLengthMapper.selectCount(queryWrapper1);
        if (integer1 == null || integer1 == 0) {
            TbHrLeaveUsableLength tbHrLeaveUsableLength = new TbHrLeaveUsableLength();
            tbHrLeaveUsableLength.setCreateBy(UserUtils.getLoginAppUser().getUserId());
            tbHrLeaveUsableLength.setYear(String.valueOf(currentYear - 1));
            tbHrLeaveUsableLength.setAllOverTime(0);
            tbHrLeaveUsableLength.setOverTimeUsable(0);
            tbHrLeaveUsableLength.setAnnualLeaveUsable(0);
            tbHrLeaveUsableLengthMapper.insert(tbHrLeaveUsableLength);
        }


        // 获取当前年
        int currentNumber = 0; // 本年调休数
        int totalNumber = 0; // 上一年调休数

        if (f_flag == 1) { // 请假时间在截止时间之前
            for (TbHrApprovalLeaveTime tbHrApprovalLeaveTime : timeList) {
                totalNumber += tbHrApprovalLeaveTime.getDays().intValue();
            }
            // 查询上一年的加班可用数
            CompensatoryLeaveTimeQuery numberByUserIdAndYear = tbHrLeaveUsableLengthMapper.getNumberByUserIdAndYear(String.valueOf(currentYear - 1), UserUtils.getLoginAppUser().getUserId());
            if (numberByUserIdAndYear != null) {
                if (numberByUserIdAndYear.getSurplusTime() >= totalNumber) { // 上一年剩余数大于总数 减上一年的可用数
                    tbHrLeaveUsableLengthMapper.substractNumberByUserIdAndYear(String.valueOf(currentYear - 1), UserUtils.getLoginAppUser().getUserId(), totalNumber);
                } else { // 上一年剩余数小于总数
                    int surplusTime = numberByUserIdAndYear.getSurplusTime();
                    // 修改上一年数
                    tbHrLeaveUsableLengthMapper.substractNumberByUserIdAndYear(String.valueOf(currentYear - 1), UserUtils.getLoginAppUser().getUserId(), surplusTime);
                    // 修改本年数
                    tbHrLeaveUsableLengthMapper.substractNumberByUserIdAndYear(String.valueOf(currentYear), UserUtils.getLoginAppUser().getUserId(), totalNumber - surplusTime);
                }
            } else {
                // 修改本年数
                tbHrLeaveUsableLengthMapper.substractNumberByUserIdAndYear(String.valueOf(currentYear), UserUtils.getLoginAppUser().getUserId(), totalNumber);
            }

        }

        if (f_flag == 2) { // 请假时间在截止时间之后
            for (TbHrApprovalLeaveTime tbHrApprovalLeaveTime : timeList) {
                totalNumber += tbHrApprovalLeaveTime.getDays().intValue();
            }
            tbHrLeaveUsableLengthMapper.substractNumberByUserIdAndYear(String.valueOf(currentYear), UserUtils.getLoginAppUser().getUserId(), totalNumber);
        }

        if (f_flag == 3) { // 两者都有
            for (TbHrApprovalLeaveTime tbHrApprovalLeaveTime : timeList) {
                LocalDate stopDate = DateUtils.date2LocalDate(tbHrApprovalLeaveTime.getStopDate());
                // 请假时间大于本年度截止时间
                if (stopDate.isAfter(date)) {
                    String stopTime = tbHrApprovalLeaveTime.getStopTime();
                    String format = stopDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));

                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    Date parse = simpleDateFormat.parse(format + " " + stopTime + ":00");
                    Date parse1 = simpleDateFormat.parse(format + " 09:00:00");


                    BigDecimal dayCoincidence = MyDateUtil.getDayCoincidence(parse1, parse, parse1, parse);
                    int i = dayCoincidence.intValue();
                    currentNumber += i;

                }
                totalNumber += tbHrApprovalLeaveTime.getDays().intValue();

            }

            // 查询上一年的加班可用数
            CompensatoryLeaveTimeQuery numberByUserIdAndYear = tbHrLeaveUsableLengthMapper.getNumberByUserIdAndYear(String.valueOf(currentYear - 1), UserUtils.getLoginAppUser().getUserId());
            // 去年没有数据
            if (numberByUserIdAndYear == null) {
                // 修改本年数
                tbHrLeaveUsableLengthMapper.substractNumberByUserIdAndYear(String.valueOf(currentYear), UserUtils.getLoginAppUser().getUserId(), totalNumber);
            } else {
                int preN = totalNumber - currentNumber;

                if (numberByUserIdAndYear.getSurplusTime() > preN) {
                    // 修改上一年数
                    tbHrLeaveUsableLengthMapper.substractNumberByUserIdAndYear(String.valueOf(currentYear - 1), UserUtils.getLoginAppUser().getUserId(), preN);
                } else {
                    // 修改上一年数
                    tbHrLeaveUsableLengthMapper.substractNumberByUserIdAndYear(String.valueOf(currentYear - 1), UserUtils.getLoginAppUser().getUserId(), numberByUserIdAndYear.getSurplusTime());

                    // 修改本年数
                    tbHrLeaveUsableLengthMapper.substractNumberByUserIdAndYear(String.valueOf(currentYear), UserUtils.getLoginAppUser().getUserId(), totalNumber - numberByUserIdAndYear.getSurplusTime());
                }

            }
        }





        *//*for (TbHrApprovalLeaveTime tbHrApprovalLeaveTime : timeList) {
            int startYear = tbHrApprovalLeaveTime.getStartDate().getYear();
            int stopYear = tbHrApprovalLeaveTime.getStopDate().getYear();





            // 本年度加班
            if (startYear == currentYear && stopYear == currentYear) {
                currentNumber +=tbHrApprovalLeaveTime.getDays().intValue();
            }

            if (startYear == currentYear+1 && stopYear == currentYear+1) {
                nextNumber +=tbHrApprovalLeaveTime.getDays().intValue();
            }

            if (startYear == currentYear && stopYear == currentYear+1) {

                LocalDate stopDate = tbHrApprovalLeaveTime.getStopDate();
                String stopTime = tbHrApprovalLeaveTime.getStopTime();
                String format = stopDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));

                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date parse = simpleDateFormat.parse(format + " " + stopTime + ":00");
                Date parse1 = simpleDateFormat.parse(format + " 00:00:00");

                Long l = (parse.getTime() - parse1.getTime()) / (1 * 1000 * 60 *60);
                int i = l.intValue();
                // 下一年的加班数
                nextNumber +=i;
                // 本年度加班数
                currentNumber+= (tbHrApprovalLeaveTime.getDays().intValue()-i);
            }
        }

        if (currentNumber != 0) {
            tbHrLeaveUsableLengthMapper.substractNumberByUserIdAndYear(String.valueOf(currentYear),UserUtils.getLoginAppUser().getUserId(),currentNumber);
        }

        if (nextNumber != 0) {
            tbHrLeaveUsableLengthMapper.substractNumberByUserIdAndYear(String.valueOf(currentYear+1),UserUtils.getLoginAppUser().getUserId(),currentNumber);
        }*//*
    }*/


    /**
     * 申请人请假流程重新提交
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    public ApprovalQuery returnLeaveApply(ReturnLeaveApplyDto data) throws Exception {
        TbHrApprovalLeaveApply apply = data.getApply();

        HandleAuditDto handleAudit = data.getHandleAudit();
        handleAudit.setProposerId(UserUtils.getLoginAppUser().getUserId());
        apply.setId(handleAudit.getDataId());

        // 拆分数据
        List<TbHrApprovalLeaveTime> tbHrApprovalLeaveTimes = splitDate(data.getTimeList(), apply);
        data.setTimeList(tbHrApprovalLeaveTimes);

        // 删除相对应的时间
        int i = tbHrApprovalLeaveTimeService.deleteByDataId(handleAudit.getDataId());
        if (i == 0) {
            throw new Exception("删除相对应的时间异常");
        }
        // 流程-hr请假时间表
        this.saveTbHrApprovalLeaveTime(tbHrApprovalLeaveTimes, apply);


        if (data.getApply().getVacationId() == 3) { // 年假
            TbHrUserSocialSecurity userSocialSecurity = tbHrUserSocialSecurityService.getUserSocialSecurity(UserUtils.getLoginAppUser().getUserId(),handleAudit.getDataId());
            if (userSocialSecurity == null) {

                // 删除上次的历史任务数据
                tbGlobalApprovalTaskService.delById(handleAudit.getProcessTaskId());
                tbGlobalApprovalTaskService.delHisTask(handleAudit.getBusinessId(),handleAudit.getDataId());

                TbHrUserSocialSecurity socialSecurity = data.getSocialSecurity();
                if (socialSecurity == null) {
                    throw new Exception("请上传社保凭证pdf文档");
                }
                // 社保凭证为空的话  直接让行政助理审核
                TbHrUserSocialSecurity tbHrUserSocialSecurity = new TbHrUserSocialSecurity();
                BeanUtils.copyProperties(data.getSocialSecurity(),tbHrUserSocialSecurity);
                tbHrUserSocialSecurity.setUserId(UserUtils.getLoginAppUser().getUserId());
                tbHrUserSocialSecurityService.save(tbHrUserSocialSecurity);

                return handleSocialSecurity(apply);
            }
            // 检验年假时间
            TbHrLeaveUseNum tbHrLeaveUseNum = checkTiem(tbHrApprovalLeaveTimes, userSocialSecurity);
            tbHrLeaveUseNum.setPreUseNum(tbHrLeaveUseNum.getPreUseNum() > 0 ? tbHrLeaveUseNum.getPreUseNum() : 0);
            tbHrLeaveUseNum.setUseNum(tbHrLeaveUseNum.getUseNum()>0?tbHrLeaveUseNum.getUseNum():0);
            if(tbHrLeaveUseNum.getId() != null){
                if(tbHrLeaveUseNumMapper.updateById(tbHrLeaveUseNum) != 1){
                    throw new Exception("修改年假已休表异常");
                }
            }else{
                // 修改今年年假已用时长和去年年假已用时长根据id
                tbHrLeaveUseNum.setSocialSecurityId(userSocialSecurity.getId());
                if( tbHrLeaveUseNumMapper.insert(tbHrLeaveUseNum) != 1){
                    throw new Exception("修改年假已休表异常");
                }
            }

        }

        // 执行流程
        ProcessNodeQuery processNodeVo = tbGlobalApprovalTaskService.handleAudit(handleAudit);
        // 修改请假申请

        apply.setBusinessId(handleAudit.getBusinessId());
        apply.setNodeId(processNodeVo.getNodeId());
        apply.setNodeName(processNodeVo.getNodeName());
        if (!super.save(apply)) {
            throw new Exception("保存流程-hr请假申请表异常");
        }


        // 消息参数
        return tbHrApprovalBecomeRegularApplyService.setApprovalQuery(handleAudit.getDataId(),
                4, "请假申请", processNodeVo,UserUtils.getLoginAppUser().getFullName());
    }

    /**
     * 全部请假申请列表
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    public Page<MyLeaveApplyListQuery> allLeaveApplyList(MyLeaveApplyListDto data) {
        Page<MyLeaveApplyListQuery> page = new Page(data.getPage(), data.getSize());
        return dao.allLeaveApplyList(page, data);
    }

    /**
     * 请假流程作废
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    public ApprovalQuery approvalLeaveToVoidApply(ApprovalLeaveToVoidApplyDto data) throws Exception {

        Long dataId = data.getDataId();
        TbHrApprovalLeaveApply tbHrApprovalLeaveApply = dao.selectById(dataId);



        if (StringUtils.isNotBlank(tbHrApprovalLeaveApply.getOldId()) && tbHrApprovalLeaveApply.getOldId() != 0) { // 表示销假数据 - 作废时候 回滚到之前的数据
            /*
             * 1、删除当前正在执行流程数据 和 历史流程数据
             * 2、恢复之前的请假审核历史数据
             * 3、删除历史请假时间数据
             * 4、还原到销假前的请假申请数据
             *
             * */

            // 删除当前正在执行流程数据 和 历史流程数据
            tbGlobalApprovalTaskMapper.delTaskByBusinessIdAndDataId(tbHrApprovalLeaveApply.getBusinessId(), tbHrApprovalLeaveApply.getId());
            tbGlobalApprovalTaskMapper.delHisTask(tbHrApprovalLeaveApply.getBusinessId(), tbHrApprovalLeaveApply.getId());

            // 恢复之前的请假审核历史数据
            tbGlobalApprovalHiTaskService.updateDataIdByBusInessIdAndDataId(tbHrApprovalLeaveApply.getBusinessId(), tbHrApprovalLeaveApply.getOldId(), tbHrApprovalLeaveApply.getId());

            // 删除历史请假时间数据
            tbHrApprovalLeaveHistoryTimeMapper.deleteByDataId(tbHrApprovalLeaveApply.getOldId());

            // 查询完成节点
            Long nodeId = tbGlobalWorkFlowNodeMapper.getNodeIdByName(tbHrApprovalLeaveApply.getBusinessId(), "完结");

            // 还原到销假前的请假申请数据
            dao.updateDataBeforeXj(tbHrApprovalLeaveApply.getId(), nodeId);
            return null;
        }

        dao.deleteMyLeaveApply(tbHrApprovalLeaveApply.getId());


        return null;
    }

    /**
     * 请假对应的销假列表
     *
     * @param idList
     * @author liuqinghua
     */
    public List<MyLeaveApplyListQuery> getCancellationLeaveApplyList(List<Long> idList, MyLeaveApplyListDto data) {
        return dao.getCancellationLeaveApplyList(idList, data);
    }

    /**
     * 按日期查询请假数据
     *
     * @param data
     * @author liuqinghua
     */
    public IPage<AllLeaveApplyListByLeaveDateQuery> allLeaveApplyListByLeaveDate(MyLeaveApplyListDto data) {
        Page<AllLeaveApplyListByLeaveDateQuery> page = new Page(data.getPage(), data.getSize());
        return dao.allLeaveApplyListByLeaveDate(page, data);
    }

    /**
     * 请假对应的销假列表 按日期查询
     *
     * @param idList
     * @author liuqinghua
     */
    public List<AllLeaveApplyListByLeaveDateQuery> getCancellationLeaveApplyListByLeaveDate(List<Long> idList, MyLeaveApplyListDto data) {
        return dao.getCancellationLeaveApplyListByLeaveDate(idList, data);
    }

    /**
     * 我的请假申请删除
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    public boolean deleteMyLeaveApply(Long dataId) throws Exception {
        TbHrApprovalLeaveApply leaveApply = dao.selectById(dataId);

        if (StringUtils.isNotBlank(leaveApply.getOldId()) && leaveApply.getOldId() != 0) { // 表示销假数据 - 作废时候 回滚到之前的数据
            ApprovalLeaveToVoidApplyDto leaveToVoidApplyDto = new ApprovalLeaveToVoidApplyDto();
            leaveToVoidApplyDto.setDataId(dataId);
            this.approvalLeaveToVoidApply(leaveToVoidApplyDto);
            return true;
        }

        if (leaveApply.getNodeId() == 0 || leaveApply.getNodeId() == 1) {
            int i = dao.deleteMyLeaveApply(dataId);
            if (i == 0) {
                throw new Exception("我的请假申请删除异常");
            }
        } else {
            throw new Exception("当前节点不允许删除");
        }


        return true;
    }

    /***
     * 销假
     * @author 苏小林
     * @date 2021/6/1 11:03
     * @param: data
     * @return: com.xhsj.user.utils.Message
     */
    public ApprovalQuery cancellationApply(HrLeaveApplyStartDto data) throws Exception {

        TbHrApprovalLeaveApply tbHrApprovalLeaveApply = dao.selectById(data.getApply().getId());
        if (StringUtils.isNotBlank(tbHrApprovalLeaveApply.getOldId()) && tbHrApprovalLeaveApply.getOldId() != 0) { // 表示重新提交
            return reCancellationApply(data, tbHrApprovalLeaveApply);
        }

        List<TbHrApprovalLeaveTime> timeList = data.getTimeList();
        // 原请假时间数据
        List<LeaveTimeQuery> leaveTimeList = tbHrApprovalLeaveTimeService.getLeaveTimeList(Arrays.asList(data.getApply().getId()), tbHrApprovalLeaveApply.getBusinessId());
        boolean flag = false; // 判断是否有数据修改

        if (leaveTimeList.size() == timeList.size()) {
            ourter:
            for (LeaveTimeQuery tbHrApprovalLeaveTime : leaveTimeList) { // 原数据
                String oldMd5 = Md5Utils.md5(JSON.toJSONString(tbHrApprovalLeaveTime));

                for (TbHrApprovalLeaveTime leaveTime : timeList) { // 新数据
                    if (tbHrApprovalLeaveTime.getId().equals(leaveTime.getId())) {
                        LeaveTimeQuery leaveTimeQuery = new LeaveTimeQuery();
                        BeanUtils.copyProperties(leaveTime, leaveTimeQuery);
                        String newMd5 = Md5Utils.md5(JSON.toJSONString(leaveTimeQuery));
                        if (!oldMd5.equals(newMd5)) { // 如果不相等 表示已经被修改过
                            flag = true;
                            break ourter;
                        }
                    }
                }
            }
        } else {
            flag = true;
        }
        /*
         * 请假和销假使用的是用一条申请数据，销假的时候，
         * 1、生成一个原数据id oldId,将申请审核历史数据的dataId改成oldId
         * 2、将原数据的请假时间添加到历史表中，dataId修改为oldId
         * 3、保存销假时间
         *
         * */
        if (flag) { // 表示有修改的数据
            long oldId = IdGen.snowId(); // 原数据id


            // 请假时长  小时
//            int days = timeList ==null?0:(int) timeList.stream().mapToInt(n -> n.getDays().intValue()).summaryStatistics().getSum();
            tbHrApprovalLeaveApply.setOldId(oldId);
            tbHrApprovalLeaveApply.setNodeId(null);
//            tbHrApprovalLeaveApply.setDays(new BigDecimal(days));
            tbHrApprovalLeaveApply.setCreateDate(new Date());
            tbHrApprovalLeaveApply.setNodeName("");
            tbHrApprovalLeaveApply.setXjReason(data.getApply().getXjReason());
            super.save(tbHrApprovalLeaveApply);

            /*if (tbHrApprovalLeaveApply.getVacationId() == 12) { // 调休

            }*/
            // 1、将请假申请的审核历史数据  dataId 修改成 oldId
            tbGlobalApprovalHiTaskService.updateDataIdByBusInessIdAndDataId(tbHrApprovalLeaveApply.getBusinessId(), data.getApply().getId(), oldId);
            // 2、将原数据插入历史表
            for (LeaveTimeQuery leaveTimeQuery : leaveTimeList) {
                TbHrApprovalLeaveHistoryTime tbHrApprovalLeaveHistoryTime = new TbHrApprovalLeaveHistoryTime();
                BeanUtils.copyProperties(leaveTimeQuery, tbHrApprovalLeaveHistoryTime);
                tbHrApprovalLeaveHistoryTime.setId(null);
                tbHrApprovalLeaveHistoryTime.setDataId(oldId);
                System.err.println(tbHrApprovalLeaveHistoryTime);
                tbHrApprovalLeaveHistoryTimeMapper.insert(tbHrApprovalLeaveHistoryTime);
            }

            tbHrApprovalLeaveTimeService.deleteByDataId(data.getApply().getId());

            // 3、保存销假时间
            for (TbHrApprovalLeaveTime tbHrApprovalLeaveTime : timeList) {
                tbHrApprovalLeaveTime.setId(null);
                tbHrApprovalLeaveTime.setOperationType(2);// 销假
                tbHrApprovalLeaveTimeService.save(tbHrApprovalLeaveTime);
            }

            tbHrApprovalLeaveApply.setCreateBy(UserUtils.getLoginAppUser().getUserId());
            return this.startLeaveApplyRun(tbHrApprovalLeaveApply);
        } else {
            throw new Exception("请修改请假时间后提交");
        }
    }

    /**
     * 销假重新提交
     *
     * @author 苏小林
     * @date 2021/6/2 15:11
     * @param: data
     * @return: com.xhsj.user.hr.process.query.ApprovalQuery
     */
    private ApprovalQuery reCancellationApply(HrLeaveApplyStartDto data, TbHrApprovalLeaveApply tbHrApprovalLeaveApply) throws Exception {

        List<TbHrApprovalLeaveTime> timeList = data.getTimeList();
        // 原请假时间数据
        List<LeaveTimeQuery> leaveTimeList = tbHrApprovalLeaveTimeService.getLeaveTimeList(Arrays.asList(data.getApply().getId()), tbHrApprovalLeaveApply.getBusinessId());
        boolean flag = false; // 判断是否有数据修改

        if (leaveTimeList.size() == timeList.size()) {
            ourter:
            for (LeaveTimeQuery tbHrApprovalLeaveTime : leaveTimeList) { // 原数据
                String oldMd5 = Md5Utils.md5(JSON.toJSONString(tbHrApprovalLeaveTime));

                for (TbHrApprovalLeaveTime leaveTime : timeList) { // 新数据
                    if (tbHrApprovalLeaveTime.getId().equals(leaveTime.getId())) {
                        LeaveTimeQuery leaveTimeQuery = new LeaveTimeQuery();
                        BeanUtils.copyProperties(leaveTime, leaveTimeQuery);
                        String newMd5 = Md5Utils.md5(JSON.toJSONString(leaveTimeQuery));
                        if (!oldMd5.equals(newMd5)) { // 如果不相等 表示已经被修改过
                            flag = true;
                            break ourter;
                        }
                    }
                }
            }
        } else {
            flag = true;
        }

        /*
         * 销假重新提交
         * 1、删除正在执行的任务 和 历史执行任务
         * 2、保存销假时间
         * 3、启动流程
         *
         * */
        if (flag) { // 表示有修改的数据

            // 请假时长  小时
            int days = timeList == null ? 0 : (int) timeList.stream().mapToInt(n -> n.getDays().intValue()).summaryStatistics().getSum();
            tbHrApprovalLeaveApply.setDays(new BigDecimal(days));
            tbHrApprovalLeaveApply.setCreateDate(new Date());
            tbHrApprovalLeaveApply.setXjReason(data.getApply().getXjReason());
            super.save(tbHrApprovalLeaveApply);

            if (tbHrApprovalLeaveApply.getVacationId() == 12) { // 调休

            }

            // 删除正在执行的任务 和 历史执行任务
            tbGlobalApprovalTaskMapper.delTaskByBusinessIdAndDataId(tbHrApprovalLeaveApply.getBusinessId(), tbHrApprovalLeaveApply.getId());
            tbGlobalApprovalTaskMapper.delHisTask(tbHrApprovalLeaveApply.getBusinessId(), tbHrApprovalLeaveApply.getId());

            tbHrApprovalLeaveTimeService.deleteByDataId(data.getApply().getId());
            // 3、保存销假时间
            for (TbHrApprovalLeaveTime tbHrApprovalLeaveTime : timeList) {
                tbHrApprovalLeaveTime.setId(null);
                tbHrApprovalLeaveTime.setOperationType(2);// 销假
                tbHrApprovalLeaveTimeService.save(tbHrApprovalLeaveTime);
            }

            tbHrApprovalLeaveApply.setCreateBy(UserUtils.getLoginAppUser().getUserId());
            return this.startLeaveApplyRun(tbHrApprovalLeaveApply);
        } else {
            throw new Exception("请修改请假时间后提交");
        }


    }

    // 保存销假历史时间
    public void insertLeaveHistoryTime(Date date, TbHrApprovalLeaveTime time) throws Exception {
        time.setCreateDate(date);
        time.setUpdateDate(date);
        time.setDataId(time.getId());
        TbHrApprovalLeaveHistoryTime tbHrApprovalLeaveHistoryTime = StringUtils.toJavaBean(time, TbHrApprovalLeaveHistoryTime.class);
        if (tbHrApprovalLeaveHistoryTimeMapper.insert(tbHrApprovalLeaveHistoryTime) != 1) {
            throw new Exception("保存销假历史时间异常");
        }
    }

    // 保存销假时间
    public void insertLeaveTime(Date date, TbHrApprovalLeaveTime time1) throws Exception {
        time1.setOperationType(2);
//        time1.setDataId(data.getDataId());
        time1.setCreateDate(date);
        time1.setUpdateDate(date);
        time1.setUpdateBy(time1.getCreateBy());
        time1.setDelFlag(0);
        if (tbHrApprovalLeaveTimeMapper.insertTime(time1) != 1) {
            throw new Exception("保存销假时间异常");
        }
    }

    /**
     * 获取请假原数据
     *
     * @author liuqinghua
     * @date Sep 1, 2020 10:07:11 AM
     */
    public List<AllLeaveTimeListByLeaveDateQuery> myOriginalLeaveApplyList(Long oldId) {
        return tbHrApprovalLeaveHistoryTimeMapper.myOriginalLeaveApplyList(oldId);
    }

    public IPage<FindToDoListVo> findToList(FindToDoListQuery baseParam) throws ExecutionException, InterruptedException {
        long l = System.currentTimeMillis();

        Long userId = UserUtils.getLoginAppUser().getUserId();

        List<Long> roleIds = tbGlobalRoleMapper.getRoleListByUserId(userId);
        int threadNum = 3;

        ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
        List<FindToDoListVo> allToList = Lists.newArrayList();
        try {
            CountDownLatch downLatch = new CountDownLatch(threadNum);

            allToList = Lists.newArrayList();
            Future<List<FindToDoListVo>> submit = executorService.submit(() -> {
                // 查询请假待办数据
                List<FindToDoListVo> toList = tbHrApprovalLeaveTimeMapper.findToList(userId, roleIds);
                downLatch.countDown();
                return toList;
            });

            Future<List<FindToDoListVo>> submit1 = executorService.submit(() -> {
                // 查询加班待办数据
                List<FindToDoListVo> toList1 = tbHrOvertimeApplyMapper.findToList(userId, roleIds);
                downLatch.countDown();
                return toList1;
            });

            Future<List<FindToDoListVo>> submit2 = executorService.submit(() -> {
                // 查询加班待办数据
                List<FindToDoListVo> toList1 = tbBadgesUseApplyMapper.findToList(userId, roleIds);
                downLatch.countDown();
                return toList1;
            });

            downLatch.await();
            allToList.addAll(submit.get());
            allToList.addAll(submit1.get());
            allToList.addAll(submit2.get());

            Collections.sort(allToList, (o1, o2) -> o2.getCreateDate().compareTo(o1.getCreateDate()));


        } catch (Exception e) {
            log.error("出错", e);
            throw e;
        } finally {
            executorService.shutdown();
        }

        long l1 = System.currentTimeMillis();
        System.err.println(l1 - l);

        IPage<FindToDoListVo> page = new Page<FindToDoListVo>();


        if (StringUtils.isBlank(baseParam.getType())) {
            if (allToList.size() > 10) {
                List<FindToDoListVo> findToDoListVos = allToList.subList(0, 10);
                page.setRecords(findToDoListVos);
                page.setTotal(allToList.size());
                return page;
            } else {
                page.setRecords(allToList);
                page.setTotal(allToList.size());
                return page;
            }

        } else if ("all".equals(baseParam.getType())) { // 查看所有的数据

            System.err.println((baseParam.getPage() - 1) * baseParam.getSize() + "--->" + baseParam.getPage() * baseParam.getSize());
            int page_no = (baseParam.getPage() - 1) * baseParam.getSize();
            int page_size = baseParam.getPage() * baseParam.getSize();

            if (page_size < allToList.size()) {
                page.setRecords(allToList.subList(page_no, page_size));
            } else {
                if (page_no > allToList.size()) {
                    return page;
                }
                page.setRecords(allToList.subList(page_no, allToList.size()));
            }


            page.setTotal(allToList.size());
            return page;
        }

        return null;

    }

    /**
     * @Description: 请假统计图数据
     * @Param:date 日期
     * @Author: liuqinghua
     * @Date: 2021/9/6
     */
    public List<Map<String, Integer>> getLeaveStatistics(String date) {
        // 参数日期是否是当月
        String now = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM"));
        boolean isNow = false;
        if(now.equals(date))
            isNow = true;
        return dao.getLeaveStatistics(date,isNow);
    }

    public TbHrLeaveUseNum data(Long userId,TbHrUserSocialSecurity param,int type) throws Exception {
        TbHrUserSocialSecurity entity = null;
        TbHrLeaveUseNum tbHrLeaveUseNum = null;
        if(param == null)
            entity = tbHrUserSocialSecurityMapper.getUserSocialSecurity(userId);
        else {
            entity = param;
        }
        if(entity != null) {
            // 获取年假过期时间
            QueryWrapper<TbHrLeaveSetting> queryWrapper1 = new QueryWrapper<>();
            queryWrapper1.eq("del_flag",0);
            List<TbHrLeaveSetting> list = tbHrLeaveSettingService.list(queryWrapper1);
            TbHrLeaveSetting tbHrLeaveSetting = null;
            if(list == null)
                tbHrLeaveSetting =  new TbHrLeaveSetting();
            else
                tbHrLeaveSetting = list.get(0);
            String annualLeaveExpireDate = tbHrLeaveSetting.getOverTimeExpireDate();

            // 去年年份
            LocalDate pre = LocalDate.now().minusYears(1);
            int preYear = pre.getYear();

            DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            String arrivalDate = tbHrApprovalEntryApplyMapper.getArrivalDateByUserId(userId);
            LocalDate arrival_Date = LocalDate.parse(arrivalDate, fmt);
            Long until = null;
            String a = null;
            String startTime = null;
            String endTime = null;
            String startTime1 = null;
            String endTime1 = null;

            if (arrival_Date.getYear() == preYear) { // 如果是本年度入职
                LocalDate localDate = LocalDate.parse(preYear + "-12-31", fmt);
                until = arrival_Date.until(localDate, ChronoUnit.DAYS);
                a = preYear + "-12-31";
                startTime = preYear + "-01-01";
                endTime = preYear + "-12-31";
                startTime1 = (preYear+1) + "-01-01";
                endTime1 =(preYear+1) + "-12-31";
                tbHrLeaveUseNum = data2(entity, a, until);
                data1(tbHrLeaveUseNum, userId, startTime, endTime, startTime1, endTime1,type,preYear);
            } else if (arrival_Date.getYear() < preYear) {
                // 2020开始有数据
                for (int i = arrival_Date.getYear(); i < preYear + 1; i++) {
                    LocalDate localDate =  LocalDate.parse(i + "-12-31", fmt);;
                    until = LocalDate.parse(i + "-01-01", fmt).until(localDate, ChronoUnit.DAYS);
                    if (i == arrival_Date.getYear())
                        until =arrival_Date.until(localDate, ChronoUnit.DAYS);

                    a = i + "-12-31";
                    startTime = i + "-01-01";
                    endTime = i + "-12-31";
                    startTime1 = i + 1 + "-01-01";
                    endTime1 = i + 1 + "-"+annualLeaveExpireDate;
                    int lastUseNum = 0;
                    if (tbHrLeaveUseNum != null) {
                        entity.setPreTotalNum(tbHrLeaveUseNum.getPreTotalNum());
                        if(tbHrLeaveUseNum.getLastUseNum() != null)
                            lastUseNum = tbHrLeaveUseNum.getLastUseNum();
                    }

                    tbHrLeaveUseNum = data2(entity, a, until);
                    tbHrLeaveUseNum.setLastUseNum(lastUseNum);
                    if (i == arrival_Date.getYear())
                        data1(tbHrLeaveUseNum, userId, startTime, endTime, startTime1, endTime1,type,preYear);
                    else
                        data3(tbHrLeaveUseNum, userId, startTime, endTime, startTime1, endTime1,type,i);
                }
            }

            tbHrLeaveUseNum.setYear(LocalDate.now().getYear());
            tbHrLeaveUseNum.setSocialSecurityId(entity.getId());
            if( tbHrLeaveUseNumMapper.insert(tbHrLeaveUseNum) != 1){
                throw new Exception("修改年假已休表异常");
            }

        }
        return tbHrLeaveUseNum;
    }

    public TbHrLeaveUseNum data2(TbHrUserSocialSecurity entity,String a,Long until) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        int annualLeaveLength = 0;
        LocalDate confirmDate = DateUtils.date2LocalDate(entity.getConfirmDate());
        LocalDate currentDate = LocalDate.parse(a, fmt);
        long months = currentDate.until(confirmDate, ChronoUnit.MONTHS);
        if(months == 0 && entity.getWorkingMonth() == 0){
            months = 1;
        }
        Integer workingYears = entity.getWorkingYears();
        Integer workingMonth = entity.getWorkingMonth();

        Integer totalMonths = workingYears * 12+workingMonth-Integer.valueOf(String.valueOf(months));
        int y = totalMonths / 12;
        int m = totalMonths % 12;
        entity.setCurrentWorkingYears(y);
        entity.setCurrentWorkingMonth(m);
        int year = entity.getCurrentWorkingYears();
        if (year >= 1 && year < 10) { // 0-10年 5天
            annualLeaveLength = 5;
        }
        if (year >= 10 && year < 20) { // 10-20年 10天
            annualLeaveLength = 10;
        }
        if (year >= 20) { // 20年以上 15天
            annualLeaveLength = 15;
        }
        String div = StringUtils.div(until, 365, 2);
        // 可用年假小时数
        String avail_able = StringUtils.mul(div, annualLeaveLength * 8, 0);
        // 可用年假小时数
        int preTotalNum = Integer.parseInt(avail_able);
        TbHrLeaveUseNum tbHrLeaveUseNum = new TbHrLeaveUseNum();
        if (entity != null) {

            // 去年年假数
            if (entity.getWorkingYears() == null) {
                entity.setWorkingYears(0);
            }
            if (entity.getWorkingMonth() == null) {
                entity.setWorkingMonth(0);
            }
//            int preTotalNum = service.preAvailableAnnualLeave(entity.getWorkingYears(),
//                    entity.getUserId(), entity.getWorkingMonth());
            tbHrLeaveUseNum.setPreTotalNum(preTotalNum);

        }
        return tbHrLeaveUseNum;
    }



    public TbHrLeaveUseNum data1(TbHrLeaveUseNum tbHrLeaveUseNum,Long userId, String startTime,String endTime,
                                 String startTime1, String endTime1,int type,int preDate){
        int year = LocalDate.now().getYear()-1;
        int preTotalNum = tbHrLeaveUseNum.getPreTotalNum();
        //  已修
        int date = tbHrLeaveUseNumMapper.getDate(userId,startTime,endTime);
//            去年结余
        int sum =  preTotalNum-date;
        if(type == 1 && preDate == year){
            tbHrLeaveUseNum.setPreUseNum(sum);
            return tbHrLeaveUseNum;
        }
        // 下一年年已修
        int date1 = tbHrLeaveUseNumMapper.getDate1(userId,startTime1,endTime1);
        if(sum > 0){
            if(sum>date1){
                tbHrLeaveUseNum.setPreUseNum(date+date1);
                tbHrLeaveUseNum.setLastUseNum(date1);
            }else{
                tbHrLeaveUseNum.setPreUseNum(preTotalNum);
                tbHrLeaveUseNum.setUseNum(date1-sum);
                tbHrLeaveUseNum.setLastUseNum(sum);
            }
        }else {
            tbHrLeaveUseNum.setPreUseNum(date);
        }

        return tbHrLeaveUseNum;
    }
    public TbHrLeaveUseNum data3(TbHrLeaveUseNum tbHrLeaveUseNum,Long userId, String startTime,String endTime,
                                 String startTime1, String endTime1,int type,int i){
        int year = LocalDate.now().getYear()-1;
        // 去年结余
        int preTotalNum = tbHrLeaveUseNum.getPreTotalNum();
        int preUseNum = tbHrLeaveUseNum.getPreUseNum();
//            去年结余
        int sum =  preTotalNum-preUseNum;
        // 上一年抵消了多少时间
        int lastUseNum = tbHrLeaveUseNum.getLastUseNum();
        // 下一年年已修
        int date1 = tbHrLeaveUseNumMapper.getDate1(userId, startTime1, endTime1);
        int date = tbHrLeaveUseNumMapper.getDate(userId,startTime,endTime);
        date = date -lastUseNum;
        if(userId == 282 && i==2020){
            date1 = date1-24;
        }
        if(userId == 282 && i==2021){
            date = date-24;
        }
        if(type==1 && i==year){
            return tbHrLeaveUseNum;
        }
        if(sum > 0){
            if(sum>date1){
                tbHrLeaveUseNum.setPreUseNum(date);
                tbHrLeaveUseNum.setLastUseNum(date1);
            }else{
                tbHrLeaveUseNum.setPreUseNum(preTotalNum);
                tbHrLeaveUseNum.setUseNum(date1-sum);
                tbHrLeaveUseNum.setLastUseNum(sum);
            }
        }else {
            tbHrLeaveUseNum.setPreUseNum(date);
        }
        return tbHrLeaveUseNum;
    }

    public List<TbHrApprovalLeaveApply> getList(long userId, int i) {
        return dao.getList(userId,i);
    }

    // 年假日期修改
    public void updateAnnualLeave(TbHrUserSocialSecurity tbHrUserSocialSecurity) throws Exception {
        TbHrLeaveUseNum tbHrLeaveUseNum = new TbHrLeaveUseNum();
        tbHrLeaveUseNum.setSocialSecurityId(tbHrUserSocialSecurity.getId());
        tbHrLeaveUseNum.setUseNum(tbHrUserSocialSecurity.getUseNumber());
        tbHrLeaveUseNum.setPreTotalNum(tbHrUserSocialSecurity.getPreTotalNum());
        tbHrLeaveUseNum.setPreUseNum(tbHrUserSocialSecurity.getPreUseNum());
        // 年假日期修改通过用户社保凭证表id
        int i = tbHrLeaveUseNumMapper.updateBySocialSecurityId(tbHrLeaveUseNum);
        if (i != 1) {
            throw new Exception("有异常，请联系管理员");
        }
    }
}
